React从入门到精通系列之(5)state管理和生命周期钩子
<source id="gedbf"><samp id="gedbf"><dd id="gedbf"></dd></samp></source>
<thead id="gedbf"><dl id="gedbf"><noscript id="gedbf"></noscript><del id="gedbf"><link id="gedbf"></link></del></dl></thead><tbody id="gedbf"></tbody>
      <optgroup id="gedbf"></optgroup>

    • <bdo id="gedbf"><sup id="gedbf"><div id="gedbf"><bdo id="gedbf"></bdo></div></sup></bdo>

            React从入门到精通系列之(5)state管理和生命周期钩子

            作者:日期:2017-02-19 13:15:14 点击:283

             

            State和生命周期

            考虑前面部分中的滴答时钟示例(第三章)。
            到目前为止,我们只学习了一种更新UI的方法。
            我们调用ReactDOM.render()来改变渲染输出:

            function tick() {
                const element = (
                                Hell world            It is {new Date().toLocaleTimeString()}            );
                ReactDOM.render(
                    element,
                    document.getElementById('root')
                );
            }
            setInterval(tick, 1000);

            在本节中,我们将学习如何使Clock组件真正可重用和封装。 它将设置自己的计时器并每秒更新一次。
            我们可以从封装时钟的外观开始:

            function Clock(props) {
                return (
                                hello world            It is {props.date.toLocaleTimeString()}            );
            }
            function tick() {
               ReactDOM.render(
                   ,
                   document.getElementById('root')
               );
            }
            setInterval(tick, 1000);

            然而,它缺少了一个关键要求:时钟设置一个定时器和每秒更新UI的事实应该是时钟的实现细节。理想情况下,我们要写这一次,并由时钟本身来更新时间:

            ReactDOM.render(
                ,
                document.getElementById('root')
            );

            要实现这一点,我们需要添加“state”到时钟组件。

            state类似于props,但它是私有的,完全由组件控制。

            我们之前提到,定义为类组件具有一些附加功能。 内部state就是:一个只有类组件可用的功能。

            将函数形式组件改为类形式组件

            您可以通过五个步骤将功能组件(如Clock)转换为类组件 :

            1. 创建一个与扩展React.Component相同名称的ES6类。

            2. 为它添加一个单一的空方法render()

            3. 将函数的主体移动到render()方法中。

            4. render()主体中用this.props替换props

            5. 删除剩余的空函数声明。

            class Clock extends React.Component {
               render() {
                   return (
                                      hello world               It is {this.props.date.toLocaleTimeString()}.                  )
               };
            }

            Clock现在已经重新定义为类组件而不是之前的功能组件了。
            这使我们可以使用额外的功能,如内部state和生命周期钩子。

            向类组件中添加state

            我们将分为三个步骤把dateprops移动到state

            1)在render()方法中将this.props.date替换为this.state.date
            class Clock extends React.Component {
                render() {
                    return (
                                        hello world                It is {this.state.date.toLocaleTimeString()}.                    );
                }
            }
            2)添加一个赋值初始this.state的类构造函数:
            class Clock extends React.Component {
                constructor(props) {
                    super(props);
                    this.state = {date: new Date()};
                }
                
                render() {
                    return (
                                        hello world                It is {this.state.date.toLocalTimeString()}.                    );
                }
            }

            注意我们如何将props传递给基类的构造函数:

            constructor(props) {
                super(props);
                this.state = {date: new Date()};
            }

            类组件应该总是用props调用基类构造函数。

            3)从元素中删除date prop:
            ReactDOM.render(
                ,
                document.getElementById('root')
            );

            我们稍后将定时器代码添加回组件本身。结果如下所示:

            class Clock extends React.Component {
                constructor(props) {
                    super(props);
                    this.state = {date: new Date()};
                }
                
                render() {
                   return (
                                      hello world               It is {this.state.date.toLocaleTimeString()}.                  );
                }
            }
            ReactDOM.render(
                ,
                document.getElementById('root')
            );

            接下来,我们将使时钟设置自己的定时器,并每秒更新一次。

            向类中添加声明周期方法

            在具有许多组件的应用程序中,释放组件在销毁时占用的资源非常重要。
            我们想要在第一次将时钟渲染到DOM时设置一个计时器。 这在React中称为“安装(mounting)”
            我们还想清除定时器,当时钟产生的DOM被删除。 这在React中称为“卸载(unmounting)"
            我们可以在组件类上声明特殊方法,以便在组件装入和卸载时运行一些代码:

            class Clock extends React.Component {
                constructor(props) {
                    super(props);        this.state = {date: new Date()};
                }
                
                componentDidMount() {        // 组件已经安装完毕
                }
                
                componentWillUnmount() {        // 组件将要被卸载
                }
                
                render() {
                   return (
                                      hello world               It is {this.state.date.toLocaleTimeString()}.                  );
                }
            }

            这些方法称为“生命周期钩子”
            componentDidMount()子在组件输出呈现到DOM之后运行。 这是设置计时器的好地方:

            componentDidMount() {
                this.timerID = setInterval(
                    () => this.tick(),
                    1000
                )
            }

            注意我们如何保存计时器ID就在这。
            虽然this.props是由React本身设置的,并且this.state有一个特殊的含义,如果你需要存储不用于视觉输出的东西,你可以手动地添加额外的字段到类中。
            如果你不使用render()中的东西,它不应该放置在state中。
            我们将拆除componentWillUnmount()生命周期钩子中的计时器:

            componentWillUnmount() {
                clearInterval(this.timerID);
            }

            最后,我们将实现每秒运行的tick()方法。
            它将使用this.setState()来调度组件本地state的更新:

            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 (
                                      hello world               It is {this.state.date.toLocaleTimeString()}.                  );
                }
            }
            ReactDOM.render(
                ,
                document.getElementById('root')
            );

            现在时钟每秒钟都在滴答地走,棒不棒。。。。

            让我们快速回顾一下发生了什么以及调用方法的顺序:

            • 1)当将传递给ReactDOM.render()时,React调用Clock组件的构造函数。由于Clock需要显示当前时间,它使用包括当前时间的对象初始化this.state。我们稍后将更新此state。

            • 2)React然后调用Clock组件的render()方法。这是React如何学习应该在屏幕上显示什么。 React然后更新DOM以匹配时钟的渲染输出。

            • 3)当时钟输出插入到DOM中时,React调用componentDidMount()生命周期钩子。在其中,时钟组件要求浏览器设置一个定时器,每秒调用tick()一次。

            • 4)每秒钟浏览器调用tick()方法。在其中,Clock组件通过调用setState()和包含当前时间的对象来调度UI更新。由于setState()调用,React知道state已更改,并再次调用render()方法来了解屏幕上应该显示的内容。这个时候,render()方法中的this.state.date将会不同,因此渲染输出将包括更新的时间。 React相应地更新DOM。

            • 5)如果时钟组件从DOM中被移除,React将调用componentWillUnmount()生命周期钩子,因此定时器停止。

            正确使用state

            关于setState()你应该了解三件事情:

            不要直接修改state

            例如,这将不会重新渲染组件:

            // 这是错误的this.state.comment = 'hello';

            应该使用setState()代替:

            // 这是正确的this.setState({comment: 'hello'});

            唯一可以分配this.state的地方是构造函数。

            state更新可能是异步的

            React可以将多个setState()用批处理为单个更新以实现较高的性能。
            因为this.propsthis.state可能是异步更新的,你不应该依赖它们的值来计算下一个state。
            例如,此代码可能无法更新计数器:

            // 这是错误的this.setState({
                counter: this.state.counter + this.props.increment,
            });

            要解决它,应该使用回调函数而不是对象来调用setState()。 回调函数将接收先前的state作为第一个参数,并将应用更新时的props作为第二个参数:

            // 这是正确的this.setState((prevState, props) => ({
                counter: prevState.counter + props.increment
            }));

            我们使用上面的箭头函数,但它也可以与常规函数一起使用:

            // 这同样也是正确的,将剪头函数改为普通函数
            this.setState(function(prevState, props) {
               return {
                   counter: prevState.counter + prps.increment
               }
            });
            state更新是经过合并的

            当调用setState()时,React会将您提供的对象合并到当前state。
            例如,您的state可能包含几个独立变量:

            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而已。

            数据是向下流动的

            父组件和子组件都不能知道某个组件是有State的还是无State的,并且它们不应该关心它是否为功能组件或类组件。

            这就是为什么State通常被设置为局部变量或封装到组件内部。 除了拥有和设置它的组件之外的其他任何组件都不能访问它。

            组件可以选择将其state作为props传递给其子组件:

            Is is {this.state.date.toLocaleTimeString()}.

            这也适用于用户定义的组件:


            FormattedDate组件将在其props中接收date,并且不知道它是来自时钟的stateprops还是手动输入

            function FormattedData(props) {
                return Is is {props.date.toLocaleTimeString()}.;
            }

            这通常被称为“自顶向下”“单向”数据流。 任何state总是由一些特定组件拥有,并且从该state派生的任何数据或UI只能影响树中的“下面”组件。

            如果你想象一个组件树作为props的瀑布流,每个组件的state就像一个额外的水源,它可以在任意点连接它,但也向下流。

            为了显示所有组件都是真正隔离的,我们可以创建一个App组件来渲染三个

            function App() {
                return (
                                                                    );
            }
            ReactDOM.render(
                ,
                document.getElementById('root')
            );

            每个时钟设置自己的定时器并独立更新。在React应用程序中,组件是有状态还是无状态被视为可能随时间更改的组件的实现细节。 您可以在有状态组件内使用无状态组件,反之亦然。

             

            上一篇: 使用Node实现Http代理

            下一篇: React从入门到精通系列之(6)事件处理

            73099威尼斯城73099.com |威尼斯73099.com官方网站登录 |威尼斯手机娱乐官网 | |手机版 | | 澳门威尼斯3544.com,威尼斯3544.com官网登陆,威尼斯3544.com备用网址-0327.com|威尼斯澳门官方6799.com,www.6799.com,威尼斯官方娱乐6799.com登陆-vns566.net|6799.com威尼斯手机版,6799.com威尼斯网址,6799.com威尼斯官网登陆-59859.com|86087威尼斯城86087.com,威尼斯86087.com官方网站登录,威尼斯手机娱乐官网-83855.com|澳门威利斯人手机版,www.86087.com官方入口,澳门威利斯人在线娱乐-944185.com|威尼斯澳门官方4886.com,www.4886.com,威尼斯官方娱乐4886.com登陆-k92988.com|