React入门笔记(一):简介和JSX
React入门笔记(二):组件和AJAX
React入门笔记(三):表单、事件、Ref属性
React中的Diff算法——Christopher Chedeau(原文翻译)
一、React表单
以下给出几个栗子介绍如何在React中使用表单。
最简单的例子:更新state
在实例中设置了输入框input值value={this.state.data}
。在输入框值发生变化时可以更新state。可以使用onChange
事件来监听input的变化并修改state。代码将渲染出一个值为Hello React!的input元素,并通过onChange事件响应更新用户输入的值。var HelloMessage = React.createClass({ getInitialState: function() { return {value: "Hello React!"}; }, handleChange: function(event){ this.setState({value: event.target.value}); }, render: function() { var value = this.state.value; return ( <div> <input type="text" value={value} onChange={this.handleChange} /> <h4>{value}</h4> </div> ); } }); ReactDOM.render( <HelloMessage />, document.getElementById('example') );
在子组件上使用表单:更新prop
onChange方法将触发state的更新并将更新的值传递到子组件的输入框的value上来重新渲染界面。在父组件创建事件句柄(handleChange),并作为prop(updateStateProp)传递到你的子组件上。var Content = React.createClass({ render: function() { return ( <div> <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} /> <h4>{this.props.myDataProp}</h4> </div> ); } }); var HelloMessage = React.createClass({ getInitialState: function() { return {value: 'Hello React!'}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function() { var value = this.state.value; return ( <div> <Content myDataProp={value} updateStateProp={this.handleChange}></Content> </div> ); } }); ReactDOM.render( <HelloMessage />, document.getElementById('example') );
二、React事件
最简单的例子:更新state
以下栗子通过onClick
事件来修改数据:var HelloMessage = React.createClass({ getInitialState: function() { return {value: 'Hello React!'}; }, handleChange: function(event) { this.setState({value: 'Hi~'}); }, render: function() { var value = this.state.value; return ( <div> <button onClick={this.handleChange}>点击</button> <h4>{value}</h4> </div> ); } }); ReactDOM.render( <HelloMessage />, document.getElementById('example') );
在子组件上响应事件:prop
当需要从子组件中更新父组件的state时,需要在父组件创建事件句柄(handleChange),并作为prop(updateStateProp)传递到子组件上,栗子如下:var Content = React.createClass({ render: function() { return ( <div> <button onClick={this.props.updateStateProp}>点击</button> <h4>{this.props.myDataProp}</h4> </div> ); } }); var HelloMessage = React.createClass({ getInitialState: function() { return {value: 'Hello React!'}; }, handleChange: function(event) { this.setState({value: 'Hi~'}); }, render: function() { var value = this.state.value; return ( <div> <Content myDataProp={value} updateStateProp={this.handleChange}></Content> </div> ); } }); ReactDOM.render( <HelloMessage />, document.getElementById('example') );
三、React Refs
组件并不是真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟DOM(virtual DOM)。只有当组件插入文档之后,才会变成真实的DOM。根据React的设计,所有的DOM变动,都现在虚拟DOM上发生,然后再将实际发生变动的部分反映在真实DOM上,这种算法叫做DOM diff,它可以极大提高网页的性能表现。
当需要从组件获取真实DOM的节点时,就需要用到一种非常特殊的属性Ref,可以用来绑定到render()
输出的任何组件上。这个特殊的属性允许开发者引用render()
返回的相应的支撑实例(backing instance),这样就可以确保在任何时间总是拿到正确的实例。
组件支撑实例是React在其文档的各处可引用的真实DOM节点。
使用方法
绑定一个ref属性到render的返回值上:<input ref="myInput" />
在其他代码中,通过
this.refs
获取支撑实例:var input = this.refs.myInput; var inputValue = input.value; var inputRect = input.getBoundingClientRect();
完整实例
使用this
来获取当前React组件,或使用ref来获取组件的引用,实例如下:var MyComponent = React.createClass({ handleClick: function() { // 使用原生的DOM API获取焦点 this.refs.myInput.focus(); }, render: function() { // 当组件插入到DOM后,ref属性添加一个组件的引用到`this.refs` return ( <div> <input type="text" ref="myInput" /> <input type="button" value="点击按钮后输入框获取焦点" onClick={this.handleClick} /> </div> ); } }); ReactDOM.render( <MyComponent />, document.getElementById('example') );
上述栗子中,获取了输入框的支撑实例的引用,点击按钮之后输入框获取焦点。也可以使用
getDOMNode()
方法获取DOM元素。
需要注意的是,由于this.refs.[refName]
属性获取的是真实DOM,所以必须等到虚拟DOM插入文档之后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定Click
事件的回调函数,确保了只有等到真实DOM发生Click
事件之后,才会读取this.refs.[refName]
属性。
React组件支持的事件很多,如Click
、KeyDown
、Copy
、Scroll
等,完整的事件清单可看官方文档或者在稍后的博客中会给出附录介绍。