帮助你们进一步了解React,帮助你们写出高效的可读性好的代码。html
/** * @fileoverview react组件内方法编写顺序 */ define(function(require, exports, module) { var ReactComponent = React.createClass({ propTypes: {}, contextTypes: {}, childContextTypes: {}, getDefaultProps: function() {}, getInitialState: function() {}, getChildContext: function() {}, // 组件生命周期方法 componentWillMount: function() {}, componentDidMount: function() {}, componentWillReceiveProps: function() {}, shouldComponentUpdate: function() {}, componentWillUpdate: function() {}, componentDidUpdate: function() {}, componentWillUnmount: function() {}, // 业务逻辑相关的处理方法 loadData: function() {}, parseData: function() {}, handleClick: function() {}, // 自动渲染虚拟DOM方法 render: function() {} }); module.exports = ReactComponent; });
render
,放在底部容易寻找。【正确】:react
return ( <div> <h2>title</h2> <div>content</div> </div> );
【错误】:git
return ( <h2>title</h2> <div>content</div> );
没有子节点的React组件,自闭合方式。github
【推荐】ajax
return <ComponentView/>;
【不推荐】数组
return <ComponentView></ComponentView>;
含有子节点的React组件promise
【推荐】异步
return ( <ComponentView> <ComponentChild/> </ComponentView> );
组件含有属性。ui
【推荐】this
// 属性少,一行能放下放在一行 return <ComponentView className="list-wrap" rel="list"/>; // 属性多,>3个。多行显示。 return ( <ComponentView className="list-wrap" rel="list" onClick={this.handleClick} ... /> ); // 若是属性不少的话,推荐使用以下方式。把全部属性放在一个对象里面。 var props = { className: 'list-wrap', rel: 'list', onSuccess: this.onSuccess onError: this.onSuccess }; return <ComponentView {...props}/>;
【不推荐】
return <ComponentView className="list-wrap" rel="list"/>;
子组件的渲染条件根据props\state的数据
【推荐】:先声明-》根据条件处理子组件-》{ReactElement}
module.exports = React.createClass({ getInitialState: function() { return { dataLoading: true }; }, render: function() { // 声明一个变量。 var loading; if (this.state.dataLoading) { loading = <Loading/>; } // 在JSX模板中,使用大括号{},引入子组件。 return ( <div> {loading} </div> ); } });
遍历数组经常使用方式。2种方式:map方法和forEach方法。
【Array.map方法】
var List = React.createClass({ getDefaultProps: function() { return { data: [{ name: 'test1' },{ name: 'test2' }] }; }, getInitialState: function() { return { data : this.props.data }; }, render: function(){ return ( <ul> { this.state.data.map(function(item, index){ return <li>{item.name}</li> }) } </ul> ); } });
【Array.forEach方法】
var List = React.createClass({ getDefaultProps: function() { return { data: [{ name: 'test1' },{ name: 'test2' }] }; }, getInitialState: function() { return { data : this.props.data }; }, render: function(){ var items; this.state.data.forEach(function(item, index){ items.push(<li>{item.name}</li>); }) return ( <ul> {items} </ul> ); } });
若是想在this.setState以后立马获取新的state的值或者进行一些操做,能够在回调中执行
this.setState({ coin: 111 }, funtion(){ console.log(this.state); // 新的state对象 // 其余指定操做 }) console.log(this.state); // 旧的state对象
refs getDOMNode()
使用步骤:
ref="name"
属性对一个 DOM节点进行标记this.refs.name.getDOMNode()
获取到这个节点的原生 DOM。一、示例(原生组件-》HTML标签):
获取原生DOM节点以后,就能够使用它拥有的属性以及方法。
<input ref="myInfo" data-id="xxx"/> var input = this.refs.myInfo.getDOMNode(); // 获取value var inputValue = input.value; // 自定义属性 var inputAttr = input.getAttributes('data-id'); // 失去焦点 input.blur(); // 得到焦点 input.focus();
二、示例(自定义组件-》React组件):
<List ref="list" data={data} /> var list = this.refs.list.getDOMNode(); // 修改子组件实例的状态,触发render list.setState({ data: newData }); // 能够使用子组件实例中的方法 ...
【注意】:
因为 this.refs.name.getDOMNode()
获取到是真实的DOM,必须等虚拟DOM节点插入文档中后,才能用到这个属性,不然就会报错。
【推荐】:能够在 componentDidMount
方法中调用、存储DOM节点。
【错误使用】:在render
方法中访问refs
属性。报错!!
使用场景:移除组件前,这里能够作一些清除工做,例如清除内存,解除事件的监听等等。
被触发的条件:
componentWillUnmount
会被触发。ReactDOM.unmountComponentAtNode(container)
。container中的全部组件都会被卸载,全部子组件的componentWillUnmount
方法都会触发。componentWillUnmount
方法不会触发的例如:
var Loading = React.createClass({ getDefaultProps: function(){ return { text: '加载中' }; }, componentWillUnmount: function(){ console.log('componentWillUnmount'); }, render: function(){ return ( <div className="loading">{this.props.text}</div> ); } }); module.exports = React.createClass({ getInitialState: function() { return { dataLoading: true }; }, render: function() { var loading = null; if (this.state.dataLoading) { loading = <Loading/> } return ( <div> {loading} </div> ); } }); // 当this.state.dataLoading = false时候,<Loading/>被卸载。<Loading/>组件中的componentWillUnmount在组件卸载前会被触发。
【推荐】在componentDidMount
方法中异步加载初始数据。
var AjaxC = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 请求成功,更新state,触发render方法更新视图UI self.setState({ data: res.data }) } }); }, render: function(){ //.... } });
子组件的数据由父组件提供,父组件经过props将数据传给子组件。
组件嵌套结构 - ParentComponent - ChildComponent
实现方式:componentWillReceiveProps
var ParentComponent = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 请求成功,更新state,触发render方法更新视图UI self.setState({ avatar: res.data }) } }); }, render: function(){ return ( <div> <div> 图片地址: {this.state.avatar} </div> <ChildComponent avatar={this.state.avatar} ref="child"/> </div> ); } }); var ChildComponent = React.createClass({ getInitialState: function() { return this.copyPropsToState(this.props); }, /** * 单独一个方法。组件状态处理,依赖props */ copyPropsToState: function(props) { return { avatar: props.avatar } }, componentWillReceiveProps: function(nextProps) { this.setState(this.copyPropsToState(nextProps)); }, render: function(){ return ( <img ref="avatar" src={this.state.avatar}/> ); } });
实现方式2, 在父组件中调用this.refs.xxx.setState();
var ParentComponent = React.createClass({ componentDidMount: function(){ var self = this; var promise = $.ajax({ url:'', type: 'GET' data: '' }); promise.done(function(res){ if(res.errcode == 0) { // 请求成功,更新state,触发render方法更新视图UI self.setState({ avatar: res.data }) self.refs.child.setState({ avatar: res.data }) } }); }, render: function(){ return ( <div> <div> 图片地址: {this.state.avatar} </div> <ChildComponent avatar={this.state.avatar} ref="child"/> </div> ); } }); var ChildComponent = React.createClass({ getInitialState: function() { return { avatar: this.props.avatar || "" } }, render: function(){ return ( <img ref="avatar" src={this.state.avatar}/> ); } });
【总结】:
使用React.createClass() 建立React组件:
JSX中的事件自动绑定、而且在组件卸载的时候,自动解除绑定。
React.createClass({ render: function(){ return ( <input type="text" onClick={this.handleClick}/> ); }, handleClick: function(e){ // this为当前组件实例对象。 this.setStata({ data: '11' }) } }); // 若事件须要传参数 React.createClass({ render: function(){ return ( <input type="text" onClick={this.handleClick.bind(this, '传的参数')}> ); }, /** * @param data 传的参数 * @param e event对象 */ handleClick: function(data, e){ console.log(data) // => "传的参数" // 获取发生点击事件的DOM节点,使用方式同之前。 var target = e.currentTarget; // this为当前组件实例对象。 this.setStata({ data: '11' }) } });
扩展,暂时不须要掌握【ES6语法建立React组件】
JSX中的事件,须要手动绑定到当前组件的实例对象上,使得事件方法中的this指向的是该组件实例对象.
<input type="text" onClick={this.handleClick.bind(this)}/>
【推荐】:在 componentDidMount
方法中绑定普通的DOM事件,而且在componentWillUnmount
中移除这些事件
var Scroll = React.createClass({ componentDidMount: function(){ // 请求数据 this.loadData(); // 绑定事件 this.bindEvent(); }, componentWillUnmount: function(){ console.log('off scroll event'); $(window).off('scroll'); }, loadData: function(){ //... }, bindEvent: function(){ console.log('bind scroll event'); $(window).on('scroll', function() { // 事件滚动操做 }); }, render: function(){ } });
https://facebook.github.io/react/docs/context-zh-CN.html
实践场景:
App中全局信息,组件嵌套层级很深,处于深处的子组件须要用到顶级的数据。若数据经过props方式一级一级往下传,很麻烦。能够经过此方式,让子组件访问到该数据
// 1. 在上级组件中,经过childContextTypes属性和getChildContext方法,定义组件可访问的数据(还能够是方法)。
var Parent = React.createClass({
childContextTypes: {
goldCoin: React.PropTypes.any,
getColdCoin: React.PropTypes.any,
updateGoldCoin:React.PropTypes.any,
},
getChildContext: function(){
return {
goldCoin: this.state.goldCoin, // 第一次渲染组件时,就固定了子组件获取的值。
getGoldCoin: this.getGoldCoin, // 若是n数据是变动的,推荐使用方法去获取
updateGoldCoin: this.updateGoldCoin
}
},
updateGoldCoin: function(goldCoin){
this.setState({
goldCoin: goldCoin
});
},
getGoldCoin: function(){
return Number(this.state.goldCoin);
}
})
// 2. 子组件中,能够经过this.context.xxx访问上级顶级的数据或者方法
var Child = React.createClass({
contextTypes: {
goldCoin: React.PropTypes.any,
getColdCoin: React.PropTypes.any,
updateGoldCoin: React.PropTypes.any
},
...
render: function(){
...
},
...
updateGoldCoin: function(){
var goldCoin = this.context.getGoldCoin();
var newGoldCoin = '333333';
this.context.updateGoldCoin(newGoldCoin);
}
});