前言
可能大家會問:“官網示例那麼簡單,有必要講解嗎?”,我的看法是:“非常需要!”。一般而言,官方文檔是學習新知識最好的去處,你可以瞭解它的理念、思想、模式和API等等,可謂是無所不包。相對來說,官網的Sample就是能快速的瞭解和切入的直觀體現。因此,今天來看看官網的示例要告訴我們什麼,相信它對感興趣React但是不是很瞭解的人可以有個感性的瞭解。
什麼是React(個人見解/官方簡介轉述)
- 它只做UI層面的事,你可以理解為是Web Component的特殊實現
- Virtual DOM,就一個字:“快”,同時支持服務端渲染
- 數據流,單向的數據綁定足夠應付大部分的業務場景,同時使得數據和事件的流動變得清晰
怎麼開始用上React
這裡我們先不用Webpack、gulp這些這麼“高級”的工具,方便小白入門。 我們直接引入對應的腳本更加方便,大概是這樣子的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Sample 1</title>
</head>
<body>
<div id="container"></div>
<script src="http://cdn.bootcss.com/babel-core/5.8.34/browser.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-with-addons.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-dom.js"></script>
<script type="text/babel">
var mountNode = document.getElementById('container');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>
}
});
ReactDOM.render(<HelloMessage name="SASUKE40" />, mountNode);
</script>
</body>
</html>
這是官網的第一個示例,當然官網略去了很多東西沒說。 先說一下上面代碼我加了的東西:
browser.js
是babel
的瀏覽器版本,babel
是一個很酷的東西,自己Google下就知道有多酷。提示一下,千萬別急著用babel6,你會用哭的~react
就不必多說了,我們的主角react-dom
是最近從react
拆出來的,以前是包在react
中的
細心的朋友可能看到type="text/babel"
這個奇怪的類型屬性,其實它是為了讓babel能去轉換jsx
成瀏覽器讀得懂兼容較好的JavaScript
示例初步講解
為什麼說初步呢?因為深挖底層具體的動作,可能很多人都會暈,所以只講表層我們看的到的東西。
第一個官方示例主要分成兩個步驟:
創建React類,使用
React.createClass
創建,傳入一個object, 這個object有個成員屬性render返回jsx
用ReactDOM如渲染並掛載到某個具體的DOM節點上
額外的Tip:在這裡的
<div>Hello {this.props.name}</div>
這一部分並不是HTML,而是貨真價實的JavaScript,並且創建出來對象是React實例,並不是HTML的DOM節點。
使用React在這個示例的好處
可以自定義標籤屬性,在渲染的時候可以插入到內容中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Sample 2</title>
</head>
<body>
<div id="container"></div>
<script src="http://cdn.bootcss.com/babel-core/5.8.34/browser.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-with-addons.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-dom.js"></script>
<script type="text/babel">
var mountNode = document.getElementById('container');
var Timer = React.createClass({
getInitialState: function() {
return {secondsElapsed: 0};
},
tick: function() {
this.setState({secondsElapsed: this.state.secondsElapsed + 1})
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function() {
return (
<div>過去了:{this.state.secondsElapsed}秒</div>
)
}
});
ReactDOM.render(<Timer/>, mountNode);
</script>
</body>
</html>
這個示例多了好多:
getInitialState
是一個關鍵的成員屬性,它可以初始化state,在render中可以調用this.state.xxx
就能拿到tick
是一個自定義的成員屬性,其中this.setState
是React類的關鍵方法,可以修改state的值componentDidMount
顧名思義,在掛載後執行一些東西,這裡是弄了個定時器componentWillUnmount
也顧名思義,將要卸載的時候做點事情,良好的編碼習慣,這裡清除定時
示例3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Sample 3</title>
</head>
<body>
<div id="container"></div>
<script src="http://cdn.bootcss.com/babel-core/5.8.34/browser.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-with-addons.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-dom.js"></script>
<script type="text/babel">
var mountNode = document.getElementById('container');
var TodoList = React.createClass({
render: function() {
var createItem = function(item) {
return <li key={item.id}>{item.text}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([{text: this.state.text, id: Date.now()}]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
ReactDOM.render(<TodoApp />, mountNode);
</script>
</body>
</html>
關鍵點:
標籤可以嵌套
可以些一些事件,以自定義事件函數體現,不管這裡的是JavaScript的事件,並不是DOM節點上定義的
列表組件定義的一種推薦寫法:
this.props.items.map
傳入單個組件
示例4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Sample 4</title>
</head>
<body>
<div id="container"></div>
<script src="http://cdn.bootcss.com/babel-core/5.8.34/browser.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-with-addons.js"></script>
<script src="http://cdn.bootcss.com/react/0.14.7/react-dom.js"></script>
<script src="http://cdn.bootcss.com/marked/0.3.5/marked.js"></script>
<script type="text/babel">
var mountNode = document.getElementById('container');
var MarkdownEditor = React.createClass({
getInitialState: function() {
return {value: 'Type some *markdown* here!'};
},
handleChange: function() {
this.setState({value: this.refs.textarea.value});
},
rawMarkup: function() {
return { __html: marked(this.state.value, {sanitize: true}) };
},
render: function() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
ref="textarea"
defaultValue={this.state.value} />
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.rawMarkup()}
/>
</div>
);
}
});
ReactDOM.render(<MarkdownEditor />, mountNode);
</script>
</body>
</html>
關鍵點:
可以使用自定義函數用作過濾器,如這裡引入的
marked.js
裏的marked()
React中的設置HTML的API
dangerouslySetInnerHTML
,返回含有__html
屬性的object即可- 使用
refs
拿到DOM?思考一下是不是吧~
額外的Tip:React還沒有1.0.0,很多都經常變化,
refs
在以前不是這麼拿到,哭死我們這些前端小白了~
結語
前端之路還很長,React大法好啊~