React入门系列 - 3 state与props

栏目: 服务器 · 发布时间: 5年前

内容简介:我们要认识到,React中的组件其实是一个函数,所以state是函数内部的私有变量,外部其他组件或者方法都是无法直接访问到内部的state。 而state主要被设计用于维持组件内部私有状态。初始化state需要在class中在这个代码中,我们初始化了

我们要认识到,React中的组件其实是一个函数,所以state是函数内部的私有变量,外部其他组件或者方法都是无法直接访问到内部的state。 而state主要被设计用于维持组件内部私有状态。

3.1.1 初始化state

初始化state需要在class中 constructor 进行。

import React, { PureComponent } from 'react'

export default class index extends PureComponent {
  constructor(props){
    super(props)
    this.state = {name:'demo react',time:new Date()}
  }
  render() {
    return (
      <div>
        Hello world React!{this.state.name}
        <p>组件生成时间:{this.state.time}</p>
      </div>
    )
  }
}

复制代码

在这个代码中,我们初始化了 name , time 两个state值。一旦state初始化完成,我们就可以在render中进行访问。

使用 npm run dev 命令运行,并在浏览器中打开查看吧。

3.1.2 修改state值setState

我们已经知道了如何初始化组件中的state值,那么接下来我们来看看,如何实现修改state的值

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      this.state.time = (+new Date())
    }
    render() {
      return (
        <div>
          Hello world React!{this.state.name}
          <p>组件生成时间:{this.state.time}</p>
          <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
        </div>
      )
    }
  }
复制代码

有些动作快的同学,第一个想法就是如此修改组件中的 state 值,但是值得玩味的是,值的确是修改成功了,但是,并没有实时体现在界面上。这究竟是怎么回事呢?

这就要来看看,React中的 setState 方法。

React对于 setState 的定义为请求React修改某个数据,而React的实现则是将对变量的修改放入一个修改队列中,在一个循环之后进行批量更新结果(深入点涉及VDom的更新机制)。所以,这里会造成一个问题,就是 setState 数据之后立刻进行读取,可能你读取到的数据,并非是已经被更新过的有效值。

setState有三种修改数据的方式,让我们来一个一个尝试。

3.1.2.1 直接赋值

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      // this.state.time = (+new Date())
      console.log('修改前的值',this.state.time)
      this.setState({time:+new Date()})
      console.log('修改后的值',this.state.time)
      let that = this
      setTimeout(function(){
          console.log('当前state值',that.state.time)
      })
    }
    render() {
      return (
        <div>
          Hello world React!{this.state.name}
          <p>组件生成时间:{this.state.time}</p>
          <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
        </div>
      )
    }
  }

复制代码

点击按钮,控制台输出了不同的值,可以观察到 setState 是采用异步队列模式的。

React入门系列 - 3 state与props

3.1.2.2 赋值完成等待同步完成之后执行回调

现在出现了一个问题,如果我们需要通过等待 setState 修改完成的值之后,应该如何处理?React为我们的 setState 提供了第二个参数 callback

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      // this.state.time = (+new Date())
      console.log('修改前的值',this.state.time)
      this.setState({time:+new Date()},(function(){
          console.log('当前state值',that.state.time)
      })
      console.log('修改后的值',this.state.time)
    }
    render() {
      return (
        <div>
          Hello world React!{this.state.name}
          <p>组件生成时间:{this.state.time}</p>
          <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
        </div>
      )
    }
  }

复制代码

再次运行,并且点击按钮。我们可以看到控制台输出的值是跟第一个方法是一致的。

React入门系列 - 3 state与props

现在我们来进行一次脑暴,可不可以直接修改state值呢?因为我们在最早直接对state修改的时候,React并未关闭这个对象的 set 方法。那么我们可否直接通过修改 state 来进行渲染呢?React中的一个方法为我们解决了这个疑问。

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
        console.log("修改前的值", this.state.time);
        this.state.time = (+new Date())
        console.log("修改后的值", this.state.time);
        console.log("当前state值", this.state.time);
        this.forceUpdate()
    }
    render() {
      return (
        <div>
          Hello world React!{this.state.name}
          <p>组件生成时间:{this.state.time}</p>
          <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
        </div>
      )
    }
  }
复制代码

上面这个代码仅仅用于脑暴,参考,不要在生产环境中使用,因为这个会造成React渲染算法与各种Hook失效,造成全局重新渲染。

3.1.2.3 通过原始数据进行更新

在某些场景下面,我们可能是新的值是基于上一次的值推算而来,所以React提供了 setState 传递进方法来进行推算处理。

import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { name: "demo react", time: +new Date() };
  }
  handleUpdateName() {
    console.log("修改前的值", this.state.time);
    let that = this;
    this.setState(oldData => {
      return { time: oldData.time + 1000 };
    });
    console.log("修改后的值", this.state.time);
    setTimeout(function() {
      console.log("当前state值", that.state.time);
    });
  }
  render() {
    return (
      <div>
        Hello world React!{this.state.name}
        <p>组件生成时间:{this.state.time}</p>
        <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
      </div>
    );
  }
}

复制代码

最后说一点,就是 setState 是浅拷贝,如果是结构比较深层的对象,很多同学会采用 JSON.string() 这种来进行深拷贝,这样的操作虽然说是可以的,但是非常影响性能。

React推出了 immutable 与15版本之后推出来的 PureComponent 就是为了解决这些问题的。有兴趣的同学可以搜索一下相关资料进行拓展阅读。

3.2 什么是props

我们知道,在函数中有带参数的方法,那么props其实就是传入方法中的参数。并且在React中props是只读属性。在使用场景上,是由父组件向子组件传递值的时候使用的。

3.2.1 接收并渲染props值

我们首先创建一个可以接收 props 值的组件。

import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
  }
  
  render() {
    return (
      <div style={{'background':'#fefefe'}}>
        {this.props.value||'暂无数据'}
      </div>
    );
  }
}
复制代码

接着,我们修改 Index.js 引用这个组件。

import React, { PureComponent } from "react";
import Content from './content.js'
export default class index extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { name: "demo react", time: +new Date() };
  }
  handleUpdateName() {
    this.setState({time:+new Date()})
  }
  render() {
    return (
      <div>
        Hello world React!{this.state.name}
        <p>组件生成时间:{this.state.time}</p>
        <button onClick={this.handleUpdateName.bind(this)}>修改值</button>
        <Content/>
      </div>
    );
  }
}

复制代码

这里大家有一点要注意,在React中,所有的组件名称第一个字母都必须大写,这是为了与 html 标签区分出来。

如何向子组件传值呢?就像给html标签增加属性一样。

<Content value={'我设置了' + this.state.time}/>
复制代码

这样,组件内部可以通过 props 读取到 value 值了。不过React的组件传递中有一个很有趣的属性 children ,这个的用处传递组件包含的内容。

继续修改引入组件的代码,如下

// index.js
<Content value={'我设置了' + this.state.time} >主体Children</Content>
复制代码
import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
  }
  
  render() {
    return (
      <div style={{'background':'#fefefe'}}>
        {this.props.value||'暂无数据'},children:{this.props.children}
      </div>
    );
  }
}

复制代码

最终显示效果就是这样的

React入门系列 - 3 state与props

GitHub代码地址: github.com/yodfz/learn…

原文地址: www.yodfz.com/detail/36/3…


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

思考的乐趣

思考的乐趣

顾森 / 人民邮电出版社 / 2012-6 / 45.00元

本书是一个疯狂数学爱好者的数学笔记,面向所有喜爱数学的读者。从2005年7月开始,作者已经写了连续六年的博客,积累下来了大量的数学文章。 部分文章内容被广泛关注,在网络上大量分享转载。 这本书有意挑选了初等的话题,让大大小小的读者都能没有障碍地阅读。文章内容新,让有数学背景的人也会发现很多自己没见过的初等问题。 文章是独立的。一篇文章一个话题,文章与文章之间基本不会做参考,读者可以随意跳着看......一起来看看 《思考的乐趣》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

html转js在线工具
html转js在线工具

html转js在线工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具