ReactJs组件的生命周期及其在浏览器中的工作原理
2016-03-21 09:53
453 查看
浏览器中的工作原理
2016年2月23日
15:54
1、虚拟DOM
React是很快的,因为它从不直接操作DOM。React在内存中维护一个快速响应的DOM描述。render()方法返回一个DOM的描述,React能够利用内存中的描述来快速地计算出差异,然后更新浏览器中的DOM。
另外,React实现了一个完备的虚拟事件系统,尽管各个浏览器都有自己的怪异行为,React确保所有事件对象都符合W3C规范,并且持续冒泡,用一种高性能的方式跨浏览器(andeverything bubbles consistently and in a performant waycross-browser)。你甚至可以在IE8中使用一些HTML5的事件!
大多数时候你应该呆在React的“虚拟浏览器”世界里面,因为它性能更加好,并且容易思考。但是,有时你简单地需要调用底层的API,或许借助于第三方的类似于jQuery插件这种库。React为你提供了直接使用底层DOMAPI的途径。
2、Refs和getDOMNode()
为了和浏览器交互,你将需要对DOM节点的引用。每一个挂载的React组件有一个getDOMNode()方法,你可以调用这个方法来获取对该节点的引用。
注意:
getDOMNode()仅在挂载的组件上有效(也就是说,组件已经被放进了DOM中)。如果你尝试在一个未被挂载的组件上调用这个函数(例如在创建组件的render()函数中调用getDOMNode()),将会抛出异常。
为了获取一个到React组件的引用,你可以使用this来得到当前的React组件,或者你可以使用refs来指向一个你拥有的组件。它们像这样工作:
varMyComponent = React.createClass({
handleClick: function() {
// Explicitly focus the text input usingthe raw DOM API.
this.refs.myTextInput.getDOMNode().focus();
},
render: function() {
// The ref attribute adds a reference tothe component to
// this.refs when the component is mounted.
return (
<div>
<input type="text"ref="myTextInput" />
<input
type="button"
value="Focus the textinput"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('example')
);
3、组件生命周期
组件的生命周期包含三个主要部分:
挂载: 组件被插入到DOM中。
更新: 组件被重新渲染,查明DOM是否应该刷新。
移除: 组件从DOM中移除。
React提供生命周期方法,你可以在这些方法中放入自己的代码。我们提供will方法,会在某些行为发生之前调用,和did方法,会在某些行为发生之后调用。
挂载
getInitialState(): object在组件被挂载之前调用。状态化的组件应该实现这个方法,返回初始的state数据。
componentWillMount()在挂载发生之前立即被调用。
componentDidMount()在挂载结束之后马上被调用。需要DOM节点的初始化操作应该放在这里。
更新
componentWillReceiveProps(object nextProps)当一个挂载的组件接收到新的props的时候被调用。该方法应该用于比较this.props和nextProps,然后使用this.setState()来改变state。
shouldComponentUpdate(object nextProps, object nextState): boolean当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.props和nextProps,以及this.state和nextState的比较,如果不需要React更新DOM,则返回false。
componentWillUpdate(object nextProps, object nextState)在更新发生之前被调用。你可以在这里调用this.setState()。
componentDidUpdate(object prevProps, object prevState)在更新发生之后调用。
移除
componentWillUnmount()在组件移除和销毁之前被调用。清理工作应该放在这里。
挂载的方法(Mounted Methods)
挂载的复合组件也支持如下方法:
getDOMNode(): DOMElement可以在任何挂载的组件上面调用,用于获取一个指向它的渲染DOM节点的引用。
forceUpdate()当你知道一些很深的组件state已经改变了的时候,可以在该组件上面调用,而不是使用this.setState()。
4、更多
在从render 方法中返回 UI 结构之后,你可能想冲出 React 虚拟 DOM 的限制,在 render返回的组件实例上调用某些方法。通常来说,这样做对于应用中的数据流动是不必要的,因为活跃的数据( Reactive data )流总是确保最新的 props 被传递到每一个从 render() 输出的子级中去。然而,仍然有几个场景使用这种方式是必须的,或者说是有益的。
考虑这样的场景:让 <input /> 元素(存在于实例的子层级中)在值被设为空字符串 ''之后获得焦点。
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput:e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // Clearthe input
// We wish to focus the <input />now!
},
render: function() {
return (
<div>
<divonClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
注意,在示例中,我们想“告诉” input 元素一些东西 - 这些东西过会儿之后已无法从它的 props中推算出来。在这个场景中,我们想“通知” input 元素,现在应该处于获取焦点状态。然而,此处有一些障碍。从 render() 中返回的内容并不是你实际创建的子组件的组合,仅仅是一个某一刻某个组件实例的 描述 -
一个快照。
注意:
记住,从 render() 中返回的内容并不是实际渲染出来的子组件实例。从 render()返回的仅仅是子组件层级树实例在特定时间的一个描述。
这意味着千万不要紧紧抓住 render() 返回的东西不放,然后还一厢情愿地希望生成自己想象中的东西。
// counterexample: DO NOT DO THIS!
render: function() {
var myInput = <input />; // I'm going to try to call methodson this
this.rememberThisInput = myInput; // inputat some point in the future! YAY!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
在这个反例中,<input /> 仅仅是一个 <input
/> 组件的描述。该描述用于创建一个真正的 <input
/> 的支撑实例(backing instance )。
所以,我们如何与真正的 input 支撑实例( backing instance ) 交流?
完成示例
varApp = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput:e.target.value});
},
clearAndFocusInput: function() {
// Clear the input
this.setState({userInput: ''}, function(){
// This code executes after thecomponent is re-rendered
this.refs.theInput.getDOMNode().focus(); // Boom! Focused!
});
},
render: function() {
return (
<div>
<divonClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
ref="theInput"
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
在这个例子中, render 函数返回一个 <input /> 实例的描述。但是真正的实例通过this.refs.theInput 获取。只要render
返回的某个子组件带有 ref="theInput",this.refs.theInput 就会获取到正确的实例。这甚至对于更高层的( 非 DOM )组件生效,例如 <Typeaheadref="myTypeahead"
/>。
优点:
可以在组件类里面定义任何公共的方法(比如在输入之前的重置方法),然后通过 refs 来调用这些公共的方法(比如 this.refs.myTypeahead.reset() )。
管理 DOM 几乎总是需要冲出“本地”组件的限制,比如通过this.refs.myInput.getDOMNode() 获取 <input
/> 元素的底层 DOM 节点。 Refs 是做这件事唯一可靠的方式。
Refs 是被自动管理的!如果某个子级实例被销毁了,它的 ref 也会自动销毁。不用考虑内存问题(除非你自己做一些疯狂的操作,保存了什么引用)。
2016年2月23日
15:54
1、虚拟DOM
React是很快的,因为它从不直接操作DOM。React在内存中维护一个快速响应的DOM描述。render()方法返回一个DOM的描述,React能够利用内存中的描述来快速地计算出差异,然后更新浏览器中的DOM。
另外,React实现了一个完备的虚拟事件系统,尽管各个浏览器都有自己的怪异行为,React确保所有事件对象都符合W3C规范,并且持续冒泡,用一种高性能的方式跨浏览器(andeverything bubbles consistently and in a performant waycross-browser)。你甚至可以在IE8中使用一些HTML5的事件!
大多数时候你应该呆在React的“虚拟浏览器”世界里面,因为它性能更加好,并且容易思考。但是,有时你简单地需要调用底层的API,或许借助于第三方的类似于jQuery插件这种库。React为你提供了直接使用底层DOMAPI的途径。
2、Refs和getDOMNode()
为了和浏览器交互,你将需要对DOM节点的引用。每一个挂载的React组件有一个getDOMNode()方法,你可以调用这个方法来获取对该节点的引用。
注意:
getDOMNode()仅在挂载的组件上有效(也就是说,组件已经被放进了DOM中)。如果你尝试在一个未被挂载的组件上调用这个函数(例如在创建组件的render()函数中调用getDOMNode()),将会抛出异常。
为了获取一个到React组件的引用,你可以使用this来得到当前的React组件,或者你可以使用refs来指向一个你拥有的组件。它们像这样工作:
varMyComponent = React.createClass({
handleClick: function() {
// Explicitly focus the text input usingthe raw DOM API.
this.refs.myTextInput.getDOMNode().focus();
},
render: function() {
// The ref attribute adds a reference tothe component to
// this.refs when the component is mounted.
return (
<div>
<input type="text"ref="myTextInput" />
<input
type="button"
value="Focus the textinput"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('example')
);
3、组件生命周期
组件的生命周期包含三个主要部分:
挂载: 组件被插入到DOM中。
更新: 组件被重新渲染,查明DOM是否应该刷新。
移除: 组件从DOM中移除。
React提供生命周期方法,你可以在这些方法中放入自己的代码。我们提供will方法,会在某些行为发生之前调用,和did方法,会在某些行为发生之后调用。
挂载
getInitialState(): object在组件被挂载之前调用。状态化的组件应该实现这个方法,返回初始的state数据。
componentWillMount()在挂载发生之前立即被调用。
componentDidMount()在挂载结束之后马上被调用。需要DOM节点的初始化操作应该放在这里。
更新
componentWillReceiveProps(object nextProps)当一个挂载的组件接收到新的props的时候被调用。该方法应该用于比较this.props和nextProps,然后使用this.setState()来改变state。
shouldComponentUpdate(object nextProps, object nextState): boolean当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.props和nextProps,以及this.state和nextState的比较,如果不需要React更新DOM,则返回false。
componentWillUpdate(object nextProps, object nextState)在更新发生之前被调用。你可以在这里调用this.setState()。
componentDidUpdate(object prevProps, object prevState)在更新发生之后调用。
移除
componentWillUnmount()在组件移除和销毁之前被调用。清理工作应该放在这里。
挂载的方法(Mounted Methods)
挂载的复合组件也支持如下方法:
getDOMNode(): DOMElement可以在任何挂载的组件上面调用,用于获取一个指向它的渲染DOM节点的引用。
forceUpdate()当你知道一些很深的组件state已经改变了的时候,可以在该组件上面调用,而不是使用this.setState()。
4、更多
在从render 方法中返回 UI 结构之后,你可能想冲出 React 虚拟 DOM 的限制,在 render返回的组件实例上调用某些方法。通常来说,这样做对于应用中的数据流动是不必要的,因为活跃的数据( Reactive data )流总是确保最新的 props 被传递到每一个从 render() 输出的子级中去。然而,仍然有几个场景使用这种方式是必须的,或者说是有益的。
考虑这样的场景:让 <input /> 元素(存在于实例的子层级中)在值被设为空字符串 ''之后获得焦点。
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput:e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // Clearthe input
// We wish to focus the <input />now!
},
render: function() {
return (
<div>
<divonClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
注意,在示例中,我们想“告诉” input 元素一些东西 - 这些东西过会儿之后已无法从它的 props中推算出来。在这个场景中,我们想“通知” input 元素,现在应该处于获取焦点状态。然而,此处有一些障碍。从 render() 中返回的内容并不是你实际创建的子组件的组合,仅仅是一个某一刻某个组件实例的 描述 -
一个快照。
注意:
记住,从 render() 中返回的内容并不是实际渲染出来的子组件实例。从 render()返回的仅仅是子组件层级树实例在特定时间的一个描述。
这意味着千万不要紧紧抓住 render() 返回的东西不放,然后还一厢情愿地希望生成自己想象中的东西。
// counterexample: DO NOT DO THIS!
render: function() {
var myInput = <input />; // I'm going to try to call methodson this
this.rememberThisInput = myInput; // inputat some point in the future! YAY!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
在这个反例中,<input /> 仅仅是一个 <input
/> 组件的描述。该描述用于创建一个真正的 <input
/> 的支撑实例(backing instance )。
所以,我们如何与真正的 input 支撑实例( backing instance ) 交流?
完成示例
varApp = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput:e.target.value});
},
clearAndFocusInput: function() {
// Clear the input
this.setState({userInput: ''}, function(){
// This code executes after thecomponent is re-rendered
this.refs.theInput.getDOMNode().focus(); // Boom! Focused!
});
},
render: function() {
return (
<div>
<divonClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
ref="theInput"
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
在这个例子中, render 函数返回一个 <input /> 实例的描述。但是真正的实例通过this.refs.theInput 获取。只要render
返回的某个子组件带有 ref="theInput",this.refs.theInput 就会获取到正确的实例。这甚至对于更高层的( 非 DOM )组件生效,例如 <Typeaheadref="myTypeahead"
/>。
优点:
可以在组件类里面定义任何公共的方法(比如在输入之前的重置方法),然后通过 refs 来调用这些公共的方法(比如 this.refs.myTypeahead.reset() )。
管理 DOM 几乎总是需要冲出“本地”组件的限制,比如通过this.refs.myInput.getDOMNode() 获取 <input
/> 元素的底层 DOM 节点。 Refs 是做这件事唯一可靠的方式。
Refs 是被自动管理的!如果某个子级实例被销毁了,它的 ref 也会自动销毁。不用考虑内存问题(除非你自己做一些疯狂的操作,保存了什么引用)。
相关文章推荐
- React的表单组件
- React传递props
- ReactJS可复用组件
- React复合组件
- React富含交互性的动态页面
- React数据呈现
- 为什么使用React
- React初步学习
- 初步了解ReactJS
- React 入门实例学习
- react-native 错误捕捉与处理
- ReactiveX
- React.js入门必须知道的那些事
- React学习笔记。
- React Native专题
- react学习札记(三)--自己的日历控件
- React Native iOS环境搭建
- H5、React Native、Native应用对比分析
- 探索react native首屏渲染最佳实践
- ReactiveCocoa学习总结