【React初接触】(二)粗了解State和prop

346 阅读3分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

前情:创建组件 成功之后,如何处理组件内部状态的变化和组件间的传值呢?作为一个初学者,从文档看起,加点实操经验就是下文的组成了。希望有不对的地方,大佬们不吝赐教。

Props

函数组件 & class组件

注意:对于class组件来说,props 是挂载在组件上的,所以需要通过 this 获取。而对于函数组件来说,props 是传参,所以直接使用即可。

// 函数组件:接受唯一带有数据的props对象,并返回一个react元素。本质上是 js函数
function welcome(props) {
      return <h1>Hello, {props.name}</h1>
}

ReactDom.render(
    welcome,
    document.getElementById('root')
)

// class组件
class welcome extends React.component {
    render() {
        return <h1>Hello, {this.props.name}</h1>
    }
}

State

组件完全私有,仅受控于当前组件

setState

// 函数形式
this.setState((props, state) => {})

// 对象形式:同一周期内,先调用的值会被后调用的值覆盖
this.setState({ counter: 2 })

使用时注意:

  1. 不要直接修改state,需要使用 setState

    // wrong
    this.state.comment = 'hello'
    
    // correct
    this.setState({ comment: 'hello' })'
    
    
    // ----- hooks: useState -----
    
    const [visible, setVisible] = useState(false);
    
    handleVisible = (visible) => {
        setVisible(visible)
    }
    
  2. this.propsthis.state 的更新可能是异步的,所以不能依赖他们的值来更新下一个状态,需要使用 setState 的回调函数形式获得当前 stateprops

    // wrong
    this.setState({ counter: this.state.counter + this.props.increment })
    
    // correct:传参获取当前 state & props
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }))
    
    // --- or ---
    this.setState(function(state, props) {
      return { counter: state.counter + props.increment }
    })
    
  3. state 的更新会被合并

    当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state,可以分别调用 setState() 来单独地更新它们

    class MyComponent extends React.component {
      constructor(props) {
        super(props) // 将 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>This is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        )
      }
    }
    
    ReactDOM.render(<MyComponent/>, document.getElementById('root')
    
    
    /*
    1. MyComponent 传给 ReactDOM.render 时,React 调用 MyComponent 的构造函数。此时会初始化 this.state
    2. React 调用组件的 render() 方法。React更新DOM 匹配 MyComponent组件渲染的输出
    3. 当 MyComponent的输出 被插入到 DOM 之后,React调用 componentDidMount() 生命周期方法(向浏览器请求设置计时器来每秒调用一次组件的 tick() 方法)
    4. 每秒调用一次 tick()方法:组件通过调用 setState 来计划进行一次 UI更新。调用 setState 时 React 能够知道 state 已经改变了,然后会重新调用 render() 确定页面展示内容。由于 this.state.date 内容变化,MyComponent输出更新过的时间,React会更新DOM
    5. 一旦 MyComponent组件 从DOM中移除,React就会调用 componentWillUnmount() 生命周期方法,计时器停止
    */
    

结合hooks分析一下 setState

调用 setState 时,将对组件 state 的更新排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。是用于更新用户界面及响应时间处理器和处理服务器数据的主要方式。

从上述描述可知:

  1. setState是请求更新而不是立即更新组件的命令

    React会延迟调用,然后一次传递更新多个组件,不会保证 state 变更立即生效。如果出现需要 setState 之后立即读取 this.state,需要使用 componentDidUpdata or setState 的回调函数(setState(updater, callback),确保更新后触发。

  2. 除非 shouldComponentUpdate 返回false,否则 setState将始终执行重新渲染操作

  3. 如果更新返回值和当前 state 完全相同,将跳过重渲染

实操代码

import React, { useState } from 'react'
export default (props?: any) => {
    // 函数 useState,定义一个state变量count,传入初始state参数,返回 当前state和 更新state 的函数
    // 数组解构:useState返回两个值,分别自定义名称
    const [count, setCount] = useState(0); // this.count = 0
    const [fruit, setFruit] = useState('banana')
    return (
        <div>
            // 读取count
            <p>You clicked {count} times</p>
            
            // 更新count:传一个新值给setCount,react将重新渲染Example组件,并把最新的count传给它
            <button onClick={() => setCount(count + 1)}> Click me</button>
        </div>
    )
}