React学习之State与生命周期基友情(四)

我先拉拉对React-DOM输出那篇文章的知识点,从那篇文章中得知,至今为止我们只会用ReactDOM.render()去更改覆盖数据来进行视图更新,然而还是在时间的控制下进行变化。

现在我们要做的就是让组件自己跑起来

何为state?

State是一种类似于props的东西,属于组件元素的属性,但是它是私有的,并且完全被组件所控制,所以State只会存在于组件中,不是组件的话,可以走开了,并且它是可变的,而props这货是不可变的,这也是为什么State可以取代props用来实时更新视图的原因。

当然,State只是属于类组件的,不是函数式的组件的,它被作为一个类的特性与类组件绑定起来,所以函数式组件要使用State还需要转换为类组件,不然会很尴尬。

转换的步骤如下:

  1. 创建一个ES6的类继承于React.Component
  2. 增加一个简单的空函数render()
  3. .将我们的函数式组件的主体放到render()函数中
  4. render中将props替换为this.props
  5. 删除原先函数式组件的声明

其实上述步骤大家都懂,不多说了。

1.给类组件增加State状态标记数据

由于我们的props定义以后存在不可扩展和不可变性,所以用state来取代props进行数据更新变化,我们将一个数据要变为可变的,或者说想让props上的数据可变,实时更新,可以通过一下两步:

1.在render函数中,将this.props.date替换为this.state.date,如下:

class Cl extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toString()}.</h2>
      </div>
    );
  }
}

2.为类组件增加一个constructor函数去初始化this.state这个属性,如下:

class Cl 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.toString()}.</h2>
      </div>
    );
  }
}

这里我们通过superprops初始化构造函数

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

2.为类组件增加生命周期方法控制

我们将通过React挂载和卸载两个功能来实现一次Render即可更新视图,这两种功能的表现形式分别为componentDidMountcomponentWillUnmount,具体实例如下:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  componentDidMount() {
  }
  componentWillUnmount() {
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toString()}.</h2>
      </div>
    );
  }
}

componentDidMountcomponentWillUnmount,这两个方法被俗称为生命挂钩(自己取得,代表着跟组件的创建摧毁有关),componentDidMount函数会在我们render一个组件元素渲染到视图上后运行,在这里我们可以建立一个定时器,如下:

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

componentWillUnmount则是在对象摧毁时执行,一般用来摧毁我们在componentDidMount中创建的定时器

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

然后我们的更新就完成了,如下:

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.toString()}.</h2>
      </div>
    );
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

看到这些代码,大家就可以知道state是实时更新的,如此来更新界面,而去掉了反复用render处理。

这里我们整理一下,上面这份代码的函数调用步骤和实现方式。

  1. 当我们的ReactDOM.render()处理到了Clock类组件JSX时,React会调用Clock组件的构造函数constructor,用于给this.state数据进行初始化

  2. React会调用Clockrender方法,让React通过这个函数知道怎么将数据渲染到视图中,然后将数据渲染到DOM

  3. ReactClock组件的数据内嵌到DOM中后,React就会调用componentDidMount()生命周期钩,就componentDidMount中的代码而言,React会告诉浏览器,Clock类组件需要设定一个定时器,每秒钟调用一次tick

  4. 浏览器会每一秒钟调用tick函数,在tick中有一个setState函数,这个的作用就是告诉Reactstate对象被改变了,然后会自动调用render函数进行重新渲染,也就是说依旧是调用render,在上面的代码中,React自己隐性调用的,而不是我们显性调用它。

  5. 如果Clock组件从DOM中移除的话,React会调用componentWillUnmount()来将这个定时器给摧毁掉

3.请正确的使用state状态标记属性

很明显,state是一个属性,也可以看成一个对象,那么一定可以进行如下设置:

this.state.date = new Date();   

但是这样会非常费神,而且会造成代码冗余,为什么呢,感同身受的就是为一个标签设置css样式,如果没有jquerycss函数,或者是你没有写过一个比较实用的css处理函数,会发现一个非常懵逼的问题,就是属性设置写的代码能亮瞎你的眼,简直丑的一比。

所以我们这里要用jquery.css函数的使用方法为state进行设置。

this.setState({date: new Date()});

4.state更新可能会很飘

为何这么说呢?但我们一起使用多个setStatestate的状态就会有点飞。
就是说state状态对象更新可能是异步的,不是同步的。

当用如下这种形式:就会出现异步情况:

this.setState({
  counter: this.state.counter + this.props.increment,
});

上述的操作,如果出现多条的话,会造成计算失误,也就是说多个语句执行的顺序会不同从而造成结果错误。

解决方案

用函数来代替对象处理:

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
//------------------------------------
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});

这个函数格式是固定的,必须第一个参数是state的前一个状态,第二个参数是属性对象props,这两个对象setState会自动传递到函数中去,同时,这些函数在setState中的执行是同步的,从而解决了异步问题。

5.确保底层组件的透明性

组件之间耦合性越低越好,换句话说,不管是父组件还是子组件,都不知道对方是个什么鬼,不知道对方是函数式组件还是类组件,每一个组件都自我封装,只留下一个借口进行对外交互,同时只有父组件知道子组件会干啥,需要传递什么东西给子组件,而子组件却不知道父组件干了什么,可能传递了props,或者state又或是直接明了的数据,他只进行处理数据,不管数据到底怎么来的。

上述这种透明形式,官方成为自上而下,单向数据流,上层只能控制下一层的数据,无法对上层产生任何影响。

简单地说,水往低处流。

此篇博客设计的ES6的箭头函数如果大家不是很明白可以参考官方网站,当然之后,个人可能会一套ES6学习的博客,敬请期待

下一篇会将React的事件处理机制

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值