React入门方法总结
背景:
最近做了一个原型,考虑到后期没人开发,就看了看比较火的ant design react。网上搜了好几个react入门的资料,都不够全面,看起代码来还是比较费劲,下面这篇react入门写的比较好,全部过了一遍,感觉能够看懂一些代码了。
一、HTML 模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<! DOCTYPE html> < html > < head > < meta charset="utf-8"> < title >React Tutorial</ title > < script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.js"></ script > < script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></ script > < script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.6.15/browser.js"></ script > </ head > < body > < div id="content"></ div > < script type="text/babel"> // To get started with this tutorial running your own code, simply remove // the script tag loading scripts/example.js and start writing code here. </ script > </ body > </ html > |
上面代码有两个地方需要注意。
首先,最后一个 <script>
标签的 type
属性为 text/babel
。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"
。
其次,上面代码一共用了三个库: react.js
、react-dom.js
和 Browser.js
,它们必须首先加载。其中,react.js
是 React 的核心库,react-dom.js
是提供与 DOM 相关的功能,Browser.js
的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。
二、ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
1
2
3
4
|
ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById( 'content' ) ); |
三、JSX 语法
1
2
3
4
5
6
7
8
9
10
11
|
var names = [ 'monkey' , 'rabbit' , 'elephant' ]; ReactDOM.render( <div> { names.map( function (name) { return <div>Hello, {name}!</div> }) } </div>, document.getElementById( 'content' ) ); |
JSX 的基本语法规则:遇到 HTML 标签(以 <
开头),就用 HTML 规则解析;遇到代码块以 {
开头,就用 JavaScript 规则解析。
四、创建组件 React.createClass
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var CommentBox = React.createClass({ render: function () { return ( <div className= "commentBox" > Hello, world! I am a CommentBox. </div> ); } }); ReactDOM.render( <CommentBox />, document.getElementById( 'content' ) ); |
上面代码中,变量 CommentBox 就是一个组件类。模板插入 <
CommentBox />
时,会自动生成 CommentBox 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render
方法,用于输出组件。
注意:原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头。另外,组件类只能包含一个顶层标签,否则会报错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var CommentBox = React.createClass({ render: function () { return ( <div className= "commentBox" > Hello, world! I am a CommentBox. </div> <p>commont box</p> ); } }); ReactDOM.render( <CommentBox />, document.getElementById( 'content' ) ); |
注意,就是 class
属性需要写成 className
,for
属性需要写成 htmlFor
,这是因为 class
和 for
是 JavaScript 的保留字。
五、this.props
从父组件传入的数据会做为子组件的 属性( property )
,这些 属性( properties )
可以通过 this.props
访问到。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var CommentBox = React.createClass({ render: function () { return ( <div className= "commentBox" > Hello, world! I am a { this .props.author}. </div> ); } });<br> ReactDOM.render( <CommentBox author= "Pete Hunt" />, document.getElementById( 'content' ) ); |
this.props.children
访问组件内嵌的任何元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var NotesList = React.createClass({ render: function () { return ( <ol> { React.Children.map( this .props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body ); |
上面代码的 NoteList
组件有两个 span
子节点,它们都可以通过 this.props.children
读取,运行结果如下。
这里需要注意, this.props.children
的值有三种可能:如果当前组件没有子节点,它就是 undefined
;如果有一个子节点,数据类型是 object
;如果有多个子节点,数据类型就是 array
。所以,处理 this.props.children
的时候要小心。
React 提供一个工具方法 React.Children
来处理 this.props.children
。我们可以用 React.Children.map
来遍历子节点,而不用担心 this.props.children
的数据类型是 undefined
还是 object
。更多的 React.Children
的方法,请参考官方文档。
六、PropTypes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
var CommentBox = React.createClass({ propTypes: { author: React.PropTypes.string.isRequired, }, render: function () { return ( <div className= "commentBox" > Hello, world! I am a { this .props.author}. </div> ); } }); var data = 1; ReactDOM.render( <CommentBox author={data} />, document.getElementById( 'content' ) ); |
这样一来,author属性就通不过验证了。控制台会显示一行错误信息。
更多的PropTypes
设置,可以查看官方文档。
七、this.state
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var CheckboxClick = React.createClass({ getInitialState: function (){ return {checked: true }; }, handleClick: function (){ this .setState({checked: ! this .state.checked}); }, render: function (){ var text = this .state.checked ? 'checked' : 'unchecked' ; return ( <div> <input type= "checkbox" checked= "{this.props.checked}" onChange={ this .handleClick} /> <span>{text}</span> </div> ); } }); ReactDOM.render( <CheckboxClick />, document.getElementById( 'content' ) ); |
getInitialState
方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state
属性读取。
当用户点击组件,导致状态变化,this.setState
方法就修改状态值,每次修改以后,自动调用 this.render
方法,再次渲染组件。
注意:props
是不可变的:它们从父组件传递过来,“属于”父组件。为了实现交互,我们给组件引入了可变的 state。this.state
是组件私有的,可以通过调用 this.setState()
来改变它。当 state 更新之后,组件就会重新渲染自己。
八、获取真实的DOM节点(refs)
组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref
属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
var MyComponent = React.createClass({ handleClick: function () { this .refs.myTextInput.focus(); }, render: function () { return ( <div> <input type= "text" ref= "myTextInput" /> <input type= "button" value= "Focus the text input" onClick={ this .handleClick} /> </div> ); } }); ReactDOM.render( <MyComponent />, document.getElementById( 'content' ) ); |
注意:由于 this.refs.[refName]
属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click
事件的回调函数,确保了只有等到真实 DOM 发生 Click
事件之后,才会读取 this.refs.[refName]
属性。
十、组件的生命周期
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
1
2
3
4
5
|
componentWillMount() 服务器端和客户端都只调用一次,在初始化渲染执行之前立刻调用。 componentDidMount() 在初始化渲染执行之后立刻调用一次,仅客户端有效(服务器端不会调用)。 componentWillUpdate(object nextProps, object nextState) componentDidUpdate(object prevProps, object prevState) componentWillUnmount() |
此外,React 还提供两种特殊状态的处理函数。
- componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
- shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
这些方法的详细说明,可以参考官方文档。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
var Hello = React.createClass({ getInitialState: function () { console.log( 'getInitialState' ); return { opacity: 1.0 }; }, // 服务器端和客户端都只调用一次,在初始化渲染执行之前立刻调用 componentWillMount: function (){ console.log( 'componentWillMount' ); }, render: function () { console.log( 'render' ); return ( <div style={{opacity: this .state.opacity}}>Hello { this .props.name}</div> ); }, // 在初始化渲染执行之后立刻调用一次,仅客户端有效(服务器端不会调用) componentDidMount: function () { console.log( 'componentDidMount' ); this .timer = setInterval( function () { var opacity = this .state.opacity; opacity -= .05; if (opacity < 0.1) { opacity = 1.0; } this .setState({ opacity: opacity }); }.bind( this ), 200); } }); ReactDOM.render( <Hello name= "world" />, document.getElementById( 'content' ) ); |
注意: React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。
十一、Ajax
组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount
方法设置 Ajax 请求,等到请求成功,再用 this.setState
方法重新渲染 UI 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
var UserGist = React.createClass({ getInitialState: function () { return { username: '' , lastGistUrl: '' }; }, componentDidMount: function () { $.get( this .props.source, function (result) { var lastGist = result[0]; if ( this .isMounted()) { this .setState({ username: lastGist.owner.login, lastGistUrl: lastGist.html_url }); } }.bind( this )); }, render: function () { return ( <div> { this .state.username} 's last gist is <a href={this.state.lastGistUrl}>here</a>. </div> ); } }); ReactDOM.render( <UserGist source="https://api.github.com/users/octocat/gists" />, document.getElementById(' content') ); |
上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。
参考文档:
http://www.ruanyifeng.com/blog/2015/03/react.html
http://facebook.github.io/react/docs/component-specs.html#lifecycle-methods