05. react 初次见面---State&生命周期
2018-01-12 00:00
633 查看
摘要: 在本节中,我们将学习如何使Clock组件真正可重用和封装。它将设置自己的计时器,并每秒钟更新一次
到目前为止我们只学习了一种方法来更新UI。调用 ReactDOM.render( ) 方法来改变输出。
在前面博客中有一个时钟的例子代码:
将时钟封装为Clock组件
创建一个名称扩展为
创建一个叫做
将函数体移动到
在
删除剩余的空函数声明
使用类就允许我们使用其它特性,例如局部状态、生命周期钩子。
时钟组件被更改为
在 render( ) 方法中使用 this.state.date 替换 this.props.date;
添加一个类构造函数来初始化状态 this.state ;
从 <Clock /> 元素中移除 date 属性
接下来,我们将使 Clock 设置自己的计时器并每秒更新一次。
挂载:每当 Clock 组件第一次加载到 DOM 中的时候,我们都会想生产定时器,这在React中被称为挂载(componentDidMount( ){....})
卸载:每当 Clock 生产的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为卸载( componentWillUnmount( ){....} )。
这些方法被称作生命周期钩子函数。
在 componentDidMount( ) 钩子函数中建立定时器,在 componentWillUnmount( ) 钩子函数中卸载计时器。使用 this.setState( ) 来更新组件局部状态:
成功:
让我们快速回顾一下发生了什么以及调用方法的顺序:
当
React 然后调用
当
浏览器每秒钟调用
一旦
构造函数是唯一能够初始化 this.state 的地方。
因为
状态可能包含一些独立的变量:
可以调用 setState()独立更新他们:
这里的合并是浅合并,也就是说
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
组件可以选择将其状态作为属性传递给其子组件。
这通常被称为 自顶向下 或 单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。
到目前为止我们只学习了一种方法来更新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);
1. 将函数转换为类
可以通过5个步骤将函数组件 转换为 类组件创建一个名称扩展为
React.Component的ES6 类
创建一个叫做
render()的空方法
将函数体移动到
render()方法中
在
render()方法中,使用
this.props替换
props
删除剩余的空函数声明
使用类就允许我们使用其它特性,例如局部状态、生命周期钩子。
时钟组件被更改为
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
2. 为一个类添加局部状态
我们通过3个步骤将 date 从属性移动到状态中。在 render( ) 方法中使用 this.state.date 替换 this.props.date;
添加一个类构造函数来初始化状态 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> ); } }
从 <Clock /> 元素中移除 date 属性
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 设置自己的计时器并每秒更新一次。
3. 将生命周期方法添加到类中
在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。挂载:每当 Clock 组件第一次加载到 DOM 中的时候,我们都会想生产定时器,这在React中被称为挂载(componentDidMount( ){....})
卸载:每当 Clock 生产的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为卸载( componentWillUnmount( ){....} )。
这些方法被称作生命周期钩子函数。
在 componentDidMount( ) 钩子函数中建立定时器,在 componentWillUnmount( ) 钩子函数中卸载计时器。使用 this.setState( ) 来更新组件局部状态:
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ 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 />被传递给
ReactDOM.render()时,React 调用
Clock组件的构造函数。 由于
Clock需要显示当前时间,所以使用包含当前时间的对象来初始化
this.state。 我们稍后会更新此状态。
React 然后调用
Clock组件的
render()方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配
Clock的渲染输出。
当
Clock的输出插入到 DOM 中时,React 调用
componentDidMount()生命周期钩子。 在其中,
Clock组件要求浏览器设置一个定时器,每秒钟调用一次
tick()。
浏览器每秒钟调用
tick()方法。 在其中,
Clock组件通过使用包含当前时间的对象调用
setState()来调度UI更新。 通过调用
setState(),React 知道状态已经改变,并再次调用
render()方法来确定屏幕上应当显示什么。 这一次,
render()方法中的
this.state.date将不同,所以渲染输出将包含更新的时间,并相应地更新DOM。
一旦
Clock组件被从DOM中移除,React会调用
componentWillUnmount()这个钩子函数,定时器也就会被清除。
4. 正确地使用状态
关于 setState( ) 这里有三件事情需要知道4.1 不要直接更新状态
//此代码不会重新渲染组件: this.state.comment = 'Hello'; //应当使用 setState(): this.setState({comment: 'Hello'});
构造函数是唯一能够初始化 this.state 的地方。
4.2 状态更新可能是异步的
React 可以将多个setState()调用合并成一个调用来提高性能。
因为
this.props和
this.state可能是异步更新的,你不应该依靠它们的值来计算下一个状态。
//此代码可能无法更新计数器: this.setState({ counter: this.state.counter + this.props.increment, }); //正确方法是,请使用第二种形式的 setState() 来接受一个函数而不是一个对象。 该函数将接收 //先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数: this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));
4.3 状态更新合并
当你调用setState()时,React 将你提供的对象合并到当前状态。
状态可能包含一些独立的变量:
constructor(props) { super(props); this.state = { posts: [], comments: [] }; }
可以调用 setState()独立更新他们:
componentDidMount() { 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。
5. 数据自顶向下流动
父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
组件可以选择将其状态作为属性传递给其子组件。
这通常被称为 自顶向下 或 单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。
相关文章推荐
- control panel 初次见面
- Zigbee通讯漫谈(初次见面)
- 数据结构---栈----栈的初次见面
- 初次见面,请多指教——单片机
- 初次见面,CSDN博客
- Macromedia Flex 的初次见面
- 初次见面,请多指教
- (转)OO设计初次见面
- dbus实例讲解(一):初次见面
- 163. First impressions are half the battle. 初次见面,印象最深
- ORACLE存储过程(一)之初次见面
- 【C++】——初次见面
- Zigbee通讯漫谈(初次见面)
- 数据结构---栈----栈的初次见面
- JavaScript——初次见面,多多指教
- Hello Kotlin(一)初次见面
- 初次见面,请多关照
- 与Latex的初次见面
- Oracle基础-简介(初次见面)
- 数据结构---栈----栈的初次见面