React学习笔记

React笔记5(State和生命周期)

2018-07-19  本文已影响0人  XKolento

回顾:
根据目前学习内容,更新界面内容的方法为ReactDOM.render()

//定义一个方法tick,包含组件和渲染
function tick(){
    const element = <h1>{new Date().toLocalTimeString()}</h1>
    ReactDOM.render(
        element,document.getElementById('root')
    )
}
//运行方法,每秒钟重新构建元素和渲染,计时器效果
setInterval(tick,1000);
本次目的:实现clock组件的封装和可重用

1.将函数转换成class
①创建一个名为React.Component的ES6类
②创建一个render()的空方法
③把函数体移动到render(){}方法中
④在render方法中,使用this.props替换props
⑤删除剩余的空函数声明

class Clock extends React.Component{
    render(){
        return(
            <div>
                  <h1>{this.props.date.toLocaleTimeString()}</h1>
            </div>
        )
    }
}
ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
)

现在Clock被定义为一个类,而不只是一个函数,
使用类就允许我们使用它的特性,例如局部状态,生命状态钩子。

1.为了一个类添加局部状态

①将date从属性中转移到状态中
②在render()方法张使用this.state.date代替this.props.date
③添加一个类构造函数来初始化State,类组件应始终用props调用基础构造函数
④在Clock组件中,去除date属性

class Clock extends React.Component{
    constructor(){
        super(props);
        this.state = {date:new Date()};
    }
    render(){
        return(
            <h1>it is {this.state.date.toLocalTimeString()}</h1>
        )
    }
}

ReactDOM.render(
    <Clock />,document.getElementById('root')
)

2.将生命周期方法添加到类中

在具有许多组件的应用程序中,销毁时释放组件所占用的资源非常重要。
每当Clock 组件加载到DOM中,都会想要用它生成一个定时器,在React中被称为挂载
同样,每当Clock生成的这个DOM被移除时,就需要清除定时器,这被称为 卸载。
可以在组件中生命一些方法,当组件 挂载 或者 卸载时执行。

class Clock extends React.Component{
    constructor(props){
        super(props);
        this.state = {date:new Date()};
    }
    componentDidMount(){
        console.log('挂载开始')
        this.timerID = setInterval(()=>{
            this.tick();
        },1000)
    }
    componentWillUnmounte(){
        console.log('结束')
        clearInterval(this.timerID);
    }
    tick(){
        this.setState({
            date:new Date()
        })
    }
    render(){
        return(
            <div>
                  <h1>{this.state.date.toLocaleTimeString()}</h1>
            </div>
        )
    }
}
ReactDOM.render(
    <Clock />,
    document.getElementById('root')
)

以上的componentDidMount()componentWillUnmount()方法被称为生命周期钩子
当组件输出到DOM后会执行componentDidMount()方法,这时候适合建立一个定时器
步骤如下:
①当 <Clock /> 被传递给 ReactDOM.render() 时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state 。即this.state={date:new Date()};

②React 然后调用 Clock 组件的 render()方法。把React 更新 DOM 以匹配 Clock 的渲染输出。

③当 Clock 的输出插入到 DOM 中时,React 调用 componentDidMount()生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick(),此时DOM已经构建好,类似vue的mounted()

④浏览器每秒钟调用 tick()方法。 在其中,Clock 组件通过使用包含当前时间的对象调用 setState()来调度UI更新。 通过调用 setState(),React 知道状态已经改变,并再次调用 render()方法来确定屏幕上应当显示什么。 这一次,render()方法中的 this.state.date将不同,所以渲染输出将包含更新的时间,并相应地更新DOM。

⑤一旦Clock组件被从DOM中移除,React会调用componentWillUnmount()这个钩子函数,定时器也就会被清除。

从中可知:

修改this.state状态需要使用this.setState({})方法,这里有点类似微信小程序的设置方式。

3.正确的使用状态

关于this.setState({})的几个重点
①更新状态或者this.state中的内容

this.setState({comment:'hello'}); //正确修改方式
this.state.comment='hello' //错误方式
this.state.comment //获取state状态中的内容

②构造函数是唯一能够初始化this.state的地方
③状态的更新可能是异步操作导致的
React可以将多个setState({})调用合并成一个来提高性能。
因为this.propsthis.state可能是异步更新的,所以不应该根据这个来计算下一个状态的值,因为可能不是最新的数据。

这里使用第二种形式
setState({})接收一个方法,而不是一个对象,其中包含2个参数,先前的状态state作为第一个参数,应用被更新时的props作为第二个参数

// 错误的方式,计算的结果不是最新的
this.setState({
  counter: this.state.counter + this.props.increment,
});
// 正确的方式
this.setState((prevState,props)=>{
      counter:prevState.counter+props.increment
})

4.状态的更新并合并

当使用this.setState的时候,React会将当前的提供的对象合并到当前状态
状态中可能包含一些独立的变量

constructor(props){
    super(props);
    this.state({
        posts:[],
        comment:[]
    })
}

此时,可以分别调用```this.setState···独立调用他们

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

5.数据的自顶向下流动

父组件或者子组件都不能知道其他组件是否有状态state,以及组件是被定义为一个class类还是函数。
除了拥有并且设置他的组件外,其他组件不可访问内部状态。

组件可以选择将他的状态作为属性传递给其他子组件。通过this.state来获取

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

也适用于用户自定义的组件

<hello date={this.state.date} />

其中hello组件收到的date属性值,并不知道是来自Clock组件的属性还是状态。

这通常被称为 自顶向下的数据流,或者是单向数据流。任何状态始终只在某些特定的组件中,并且该状态的导出的数据或者UI视图,也只能影响 树 下方的组件。

DEMO

为了证明所有组件都是隔离的,先创建一个组件<App />

class App extends React.Component{
    render(){
        return(
            <div>
                  <Clock />
                  <Clock />
                  <Clock />
            </div>
        )
    }
}

ReactDOM.render(
    <App />,document.getElementById('root')
)

其中的每一个<Clock />会建立自己的组件并且独立更新。

上一篇 下一篇

猜你喜欢

热点阅读