React中文文档之State and Lifecycle
2016-11-17 22:53
459 查看
state 和 生命周期
到目前为止,我们仅仅学习了一种方式来更新UI。
我们调用 'ReactDOM.render()' 来改变输出渲染:
在这一小节,我们将学习如何创建真实地可重用的以及封装的Clock组件。它将建立自己的计时器,并每秒更新自身。
我们可以通过封装来开始,如下:
然而,它忽略了一个重要的需求:事实上,Clock组件建立一个计时器,并且每秒更新UI,应该是 Clock 组件的一个实现细节.
理想情况下,我们应该只写一次,Clock组件就会更新自身。
为了实现这个,我们需要添加 'state' 到 Clock 组件。
state同props非常相似,但是它是私有的,而且完全被组件自身控制
我们前面提到过,以类方式,定义的组件,有一些额外的特性。
局部state就是类可用的功能之一
将函数式组件,转换成类组件
你可以传唤一个函数式组件,例如 Clock组件,到一个类组件,通过5个步骤:
1.创建一个同名的ES6类,继承 React.Component
2.添加一个单个的render()空方法
3.移动之前的函数式组件的函数体到render()方法中
4.在render()体中,使用 'this.props' 替代 'props'
5.删除留下的空的函数声明
此时,Clock组件被定义为一个类,而不是函数
这就让我们可以使用 '附加特性',例如:局部state和生命周期钩子
向类中添加局部state
我们通过3步,将props中的data移动到state:
1.在render()方法中,使用 'this.state.data' 替换 'this.props.date'
2.添加类的构造器,分配初始的 'this.state':
注意:我们如何传入 'props' 给基础构造器(constructor)
组件类,应该总是传入 'props' 调用基础构造器
3.从<Clock />元素上,移除 'date' prop
稍后,我们将会给组件重新添加计时器
此时修改后的结果如下:
向类中添加生命周期方法:
在由许多组件组成的应用中,很重要的一点是:当组件被销毁时,释放他们占用的资源。
clock组件首次渲染为dom时,我们设置了一个计时器(set up a timer)。这在React中,被称作 'mounting'
当移除由clock组件产生的dom时,我们清除mount设置的计时器。这在React中,被称作 'unmouting'
我们可以在组件类中,声明一些特殊的方法,当组件 mount 和 unmount 时,来运行我们设置的代码:
这些方法被称作 '生命周期 钩子'
组件输出已经被渲染为dom后,运行 'componentDitMount()' 钩子。这是个设置计时器的好地方:
注意我们是如何在 'this' 对象上,保存 计时器ID的。
this.props由React自身创建,而this.state有特殊的意义,如果你需要存储一些数据,且这些数据并不用于可见输出(the visual output),你可以手动给组件类添加额外的字段
如果你在 render() 中不使用其他字段,则不应该在 state 中添加这些字段
我们将在 'componentWillunmount' 生命周期钩子中,清除计时器
最后,我们将实现 tick() 方法,将会每秒运行一次
tick() 方法,使用 'this.setState()' 来更新组件的私有state
正确使用 state
关于setState(),你应该知道3件事:
1.不要直接修改state
例如,下面的代码,将不会重新渲染组件:
使用 setState() 来代替:
2.state的更新,可能异步的
为了性能考虑,React可以在一次更新中,批量执行 setSate() 调用
因为 this.props 和 this.state 可能被异步更新,在计算接下来的state,你不应该依赖它们的值(可能还未被更新)
例如,下面的更新counter的代码可能失败:
为了修复上面的错误,使用setState()的第二种形式,接收一个函数(function),而非一个对象(object)。函数接收上一次的state作为第一个参数,更新应用时的props作为第二个参数:
上面,我们使用了一个 '箭头函数'(arrow function),也可以使用一般的函数:
3.state更新会被合并
当调用 'setState()'时,React会合并 你提供的对象(the object you provide) 到当前的state。
例如:提供的state可能包含几个独立的变量:
接着,可以使用独立的 setState() 调用来分别更新它们:
上面的合并是浅合并,因此,this.setState({comments}) 不会影响到 this.state.posts,但是会完整地替换this.state.comments
数据流向下传递(the data flows down)
父组件和子组件,都不知道某个组件是 'stateful' 还是 'stateless',而且,它们不关心它们被定义为一个函数还是类。
这就是为什么state经常被称作 局部(local) 或者 包装、封装(encapsulated)。对于除了拥有并设置它的组件之外的任意其他组件,它是不可访问的。
同 props 一样,组件也可以选择,将它的state传递给它的子组件:
对用户自定义组件也是有效的:
FormattedDate 组件接收props中的date,但是并不知道它是来自'clock' 的state,props,还是手动输入:
这通常被称为“自上而下”或“单向”的数据流。任何由某些特定组件拥有的state,任何来自该state的数据或UI,仅仅会影响树形结构中,它们的下级组件.
想象一个组件树是一个props瀑布,每个组件的state就像一个附加的水源,在任意点加入到瀑布中,但是也向下流动。
为了显示所有的组件是完全隔离的,我们可以创建一个app组件,渲染3个 clock 组件:
每个Clock设置它自己的计时器,并且独立的更新。
在React应用中,不论组件是有状态的(stateful),还是无状态的(stateless),都被认为是组件的实现细节,可以随着时间而改变。你可以在有状态的组件中使用无状态组件,反过来也一样。
到目前为止,我们仅仅学习了一种方式来更新UI。
我们调用 'ReactDOM.render()' 来改变输出渲染:
function tick() { const element = ( <div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div> ); ReactDOM.render( element, document.getElementById('root') ); } setInterval(tick, 1000);
在这一小节,我们将学习如何创建真实地可重用的以及封装的Clock组件。它将建立自己的计时器,并每秒更新自身。
我们可以通过封装来开始,如下:
function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> ); } function tick() { ReactDOM.render( <Clock date={new Date()} />, document.getElementById('root') ); } setInterval(tick, 1000);
然而,它忽略了一个重要的需求:事实上,Clock组件建立一个计时器,并且每秒更新UI,应该是 Clock 组件的一个实现细节.
理想情况下,我们应该只写一次,Clock组件就会更新自身。
ReactDOM.render( <Clock />, document.getElementById('root') );
为了实现这个,我们需要添加 'state' 到 Clock 组件。
state同props非常相似,但是它是私有的,而且完全被组件自身控制
我们前面提到过,以类方式,定义的组件,有一些额外的特性。
局部state就是类可用的功能之一
将函数式组件,转换成类组件
你可以传唤一个函数式组件,例如 Clock组件,到一个类组件,通过5个步骤:
1.创建一个同名的ES6类,继承 React.Component
2.添加一个单个的render()空方法
3.移动之前的函数式组件的函数体到render()方法中
4.在render()体中,使用 'this.props' 替代 'props'
5.删除留下的空的函数声明
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
此时,Clock组件被定义为一个类,而不是函数
这就让我们可以使用 '附加特性',例如:局部state和生命周期钩子
向类中添加局部state
我们通过3步,将props中的data移动到state:
1.在render()方法中,使用 'this.state.data' 替换 'this.props.date'
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> // 这行 </div> ); } }
2.添加类的构造器,分配初始的 'this.state':
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
注意:我们如何传入 'props' 给基础构造器(constructor)
constructor(props) { super(props); this.state = {date: new Date()}; }
组件类,应该总是传入 'props' 调用基础构造器
3.从<Clock />元素上,移除 'date' prop
ReactDOM.render( <Clock />, document.getElementById('root') );
稍后,我们将会给组件重新添加计时器
此时修改后的结果如下:
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
向类中添加生命周期方法:
在由许多组件组成的应用中,很重要的一点是:当组件被销毁时,释放他们占用的资源。
clock组件首次渲染为dom时,我们设置了一个计时器(set up a timer)。这在React中,被称作 'mounting'
当移除由clock组件产生的dom时,我们清除mount设置的计时器。这在React中,被称作 'unmouting'
我们可以在组件类中,声明一些特殊的方法,当组件 mount 和 unmount 时,来运行我们设置的代码:
class Clock extends React.Component { constructor(props) { super(props); this.state = {data: new Date()}; } componentDitMount(){ } componentWillUnmount(){ } render() { return ( <h1>It is {this.state.date.toLocaleTimeString()}.</h1> ); } }
这些方法被称作 '生命周期 钩子'
组件输出已经被渲染为dom后,运行 'componentDitMount()' 钩子。这是个设置计时器的好地方:
componentDitMount(){ this.timerID = setInterval( () => this.tick(), 1000 ); }
注意我们是如何在 'this' 对象上,保存 计时器ID的。
this.props由React自身创建,而this.state有特殊的意义,如果你需要存储一些数据,且这些数据并不用于可见输出(the visual output),你可以手动给组件类添加额外的字段
如果你在 render() 中不使用其他字段,则不应该在 state 中添加这些字段
我们将在 'componentWillunmount' 生命周期钩子中,清除计时器
componentWillunmount() { clearInterval(this.timerID); }
最后,我们将实现 tick() 方法,将会每秒运行一次
tick() 方法,使用 'this.setState()' 来更新组件的私有state
tick() { this.setState({ data: new Date(); }); }
正确使用 state
关于setState(),你应该知道3件事:
1.不要直接修改state
例如,下面的代码,将不会重新渲染组件:
this.state.comment = 'Hello'; // 错误
使用 setState() 来代替:
this.setState({comment: 'Hello'}); // 正确
2.state的更新,可能异步的
为了性能考虑,React可以在一次更新中,批量执行 setSate() 调用
因为 this.props 和 this.state 可能被异步更新,在计算接下来的state,你不应该依赖它们的值(可能还未被更新)
例如,下面的更新counter的代码可能失败:
this.setState({ counter: this.state.counter + this.props.increment; // 错误 });
为了修复上面的错误,使用setState()的第二种形式,接收一个函数(function),而非一个对象(object)。函数接收上一次的state作为第一个参数,更新应用时的props作为第二个参数:
this.setState((prevState, props) => ({ counter : prevState.counter + props.increment // 正确 }));
上面,我们使用了一个 '箭头函数'(arrow function),也可以使用一般的函数:
this.setState(function(prevState, props) { return { counter : prevState.counter + props.increment // 正确 } });
3.state更新会被合并
当调用 'setState()'时,React会合并 你提供的对象(the object you provide) 到当前的state。
例如:提供的state可能包含几个独立的变量:
constructor(props) { super(props); this.state = { posts: [], comments: [] }; }
接着,可以使用独立的 setState() 调用来分别更新它们:
componentDitMount() { fetchPosts().then(response => { this.setState({ posts: response.posts }); }); fetchComments().then(response => { this.setState({ comments: response.comments }); }); }
上面的合并是浅合并,因此,this.setState({comments}) 不会影响到 this.state.posts,但是会完整地替换this.state.comments
数据流向下传递(the data flows down)
父组件和子组件,都不知道某个组件是 'stateful' 还是 'stateless',而且,它们不关心它们被定义为一个函数还是类。
这就是为什么state经常被称作 局部(local) 或者 包装、封装(encapsulated)。对于除了拥有并设置它的组件之外的任意其他组件,它是不可访问的。
同 props 一样,组件也可以选择,将它的state传递给它的子组件:
<h2>It is {this.state.date.loLocaleTimeString()}.</h2>
对用户自定义组件也是有效的:
<FormattedDate data={this.state.date} />
FormattedDate 组件接收props中的date,但是并不知道它是来自'clock' 的state,props,还是手动输入:
function FormattedDate(props) { return <h2>It is {props.date.toLocaleTimeString()}.</h2>; }
这通常被称为“自上而下”或“单向”的数据流。任何由某些特定组件拥有的state,任何来自该state的数据或UI,仅仅会影响树形结构中,它们的下级组件.
想象一个组件树是一个props瀑布,每个组件的state就像一个附加的水源,在任意点加入到瀑布中,但是也向下流动。
为了显示所有的组件是完全隔离的,我们可以创建一个app组件,渲染3个 clock 组件:
function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') );
每个Clock设置它自己的计时器,并且独立的更新。
在React应用中,不论组件是有状态的(stateful),还是无状态的(stateless),都被认为是组件的实现细节,可以随着时间而改变。你可以在有状态的组件中使用无状态组件,反过来也一样。
相关文章推荐
- React 官方文档初释义 —— State and Lifecycle(四)
- React官方文档--State and Lifecycle
- React中文文档之Components and Props
- React中文文档之Lists and Keys
- win8: Manage app lifecycle and state 管理生命周期和状态
- Reactjs入门官方文档(四)【state-and-lifecycle】
- React Native Life Cycle and Communication
- [MST] Use Volatile State and Lifecycle Methods to Manage Private State
- ASP.NET Internals: Viewstate and Page Life Cycle(http://www.codeproject.com/KB/aspnet/aspnetviewstatepagecycle.aspx)
- React中文文档之Components and Props
- React中文教程 - Component Lifecycle(组件的生命周期)
- WCF RIA Services DomainService life-cycle and adding Transactions
- WCF RIA Services DomainService life-cycle and adding Transactions
- osgi moudle and lifecycle
- Applying Styles and Themes - 应用Style和Theme - Android官方文档中文翻译
- Flex Component Lifecycle and Flex Component Framework
- Complete Lifecycle of an ASP.Net page and controls
- Cache-and-Collect Lifecycle Management in Ninject 2.0
- 读书笔记-Review: servlet lifecycle and API
- Web Server and ASP.NET Application life Cycle in Depth [转]