React组件中的state属性

函数组件之状态,即无状态组件


使用 useState() 进行状态管理


  • useState()Hook 来启用函数组件中的状态
  • useState(initialValue)的第一个参数 initialValue是状态的初始值
  • [state, setState] = useState(initialValue)返回一个包含2个元素的数组:状态值和状态更新函数
  • 使用新值调用状态更新器函数setState(newState)更新状态。或者,可以使用一个回调 setState(prev => next)来调用状态更新器,该回调将返回基于先前状态的新状态
  • 调用状态更新器后,React 确保重新渲染组件,以使新状态变为当前状态
实例说明
import React, {
    
    useState, useEffect} from 'react';
import './App.css';

function App(props) {
    
    

    // 函数组件,即无状态组件,也可以使用状态
    /*
    * useState() 函数接受一个参数:initialState 初始状态,
    *   返回一个数组,数组内有 2 个元素,可以解构
    *       第 1 个元素:initialState,即 useState 函数传的值
    *       第 2 个元素:是 1 个函数,可以修改 initialState 值
    *           第 2 个元素函数,可以接收 3 个参数
    *           第 1 个参数:更新的内容
    *
    * */

    const [count, setCount] = useState(0);

    return (
        <div className="App">

            <p>你点击了 {
    
    count}</p>
            <button onClick={
    
    () => setCount(count + 1)}>点击</button>
        </div>
    );
}

export default App;
useState-initialState 初始状态

该初始值可以接受任何参数,但是记得当他接受为一个函数时,就变成了 Lazy initialization (延迟初始化) 该函数返回值即为 initialState

const [count, setCount] = useState(0);

const [count, setCount] = useState(()=>0);
// 这两种初始化方式 是相等的,但是在函数为初始值时会被执行一次

const [count, setCount] = useState(()=>{
    
    
    console.log('这里只会在初始化的时候执行')
    // class 中的 constructor 的操作都可以移植到这里
    return 0
});
// 当第一次执行完毕后 就和另一句的代码是相同的效果了

注意:
useState-setState
也许很多人 在使用 class 的 setState 时候,会经常使用他的回调函数,
但是这里很遗憾,他只接受新的值,如果想要对应的回调,可以使用useEffect,这个问题等会会提供一个跳转链接

多种状态


  • 通过多次调用useState(),一个函数组件可以拥有多个状态
function MyComponent() {
    
    
  const [state1, setState1] = useState(initial1);
  const [state2, setState2] = useState(initial2);
  const [state3, setState3] = useState(initial3);
  // ...
}

需要注意的,要确保对useState()的多次调用在渲染之间始终保持相同的顺序(后面会讲)。

我们添加一个按钮添加灯泡,并添加一个新状态来保存灯泡数量,单击该按钮时,将添加一个新灯泡。

新的状态count 包含灯泡的数量,初始值为1:

import React, {
    
     useState } from 'react';

function Bulbs() {
    
    
  const [on, setOn] = useState(false);
  const [count, setCount] = useState(1);

  const lightSwitch = () => setOn(on => !on);
  const addBulbs = () => setCount(count => count + 1);

  const bulb = <div className={
    
    on ? 'bulb-on' : 'bulb-off'} />;
  const bulbs = Array(count).fill(bulb);

  return (
    <>
      <div className="bulbs">{
    
    bulbs}</div>
      <button onClick={
    
    lightSwitch}>/</button>
      <button onClick={
    
    addBulbs}>添加灯泡</button>
    </>
  );
}

开关灯图

  • [on, setOn] = useState(false) 管理开/关状态
  • [count, setCount] = useState(1)管理灯泡数量。

多个状态可以在一个组件中正确工作。

状态的延迟初始化


每当 React 重新渲染组件时,都会执行useState(initialState)。 如果初始状态是原始值(数字,布尔值等),则不会有性能问题。

当初始状态需要昂贵的性能方面的操作时,可以通过为useState(computeInitialState)提供一个函数来使用状态的延迟初始化,如下所示:

function MyComponent({
    
     bigJsonData }) {
    
    
  const [value, setValue] = useState(function getInitialState() {
    
    
    const object = JSON.parse(bigJsonData); // expensive operation
    return object.initialValue;
  });

  // ...
}

getInitialState()仅在初始渲染时执行一次,以获得初始状态。在以后的组件渲染中,不会再调用getInitialState(),从而跳过昂贵的操作。

要使函数组件有状态,请在组件的函数体中调用useState()。

useState(initialState)的第一个参数是初始状态。返回的数组有两项:当前状态和状态更新函数。

const [state, setState] = useState(initialState); 使用
setState(newState)来更新状态值。
另外,如果需要根据先前的状态更新状态,可以使用回调函数setState(prevState => newState)。

在单个组件中可以有多个状态:调用多次useState()。

当初始状态开销很大时,延迟初始化很方便。使用计算初始状态的回调调用useState(computeInitialState),并且此回调仅在初始渲染时执行一次。

必须确保使用useState()遵循 Hook 规则。

当闭包捕获过时的状态变量时,就会出现过时状态的问题。可以通过使用一个回调来更新状态来解决这个问题,这个回调会根据先前的状态来计算新的状态。

最后,您将使用useState()来管理一个简单的状态。为了处理更复杂的状态,一个更好的的选择是使用useReducer() hook。

useEffect


  • 可以在 function 定义的组件中模拟生命周期
  • 参数一:表示回调函数
  • 参数二:表示什么数据改变之后会触发回调函数;
  • 若没有参数二,表示所有数据改变都会触发
  • 参数二为空数组,表示只有在第一次组件初始化的时候会触发
  • 若参数二中的数组有值,表示数组中的数据发生改变之后会触发
实例说明
useEffect(() => {
    
    
  console.log('在 dep 改变时触发,若无 dep 则,每次更新组件都会触发')
  return () => {
    
    
    console.log('在组件 unmount 时触发')
  };
});

deps 必须是一个数组,但是如果是一个空数组时:

  useEffect(() => {
    
    
    console.log('效果的等于 componentDidMount')
  }, [])

即使有 deps ,他在初始化时也会触发一次

类组件之状态


  • state 状态:存储数据
    构造函数内设置 this.state 属性,是一个对象,可以存储数据,例如:this.state = { num: 0 };

  • setState 设置状态:修改数据
    setState 是一个函数,需要调用,可以操作构造函数 this.state 对象内 的属性,并且跟新视图,且会触发 render 函数

    调用 setState 方法,通过 this.setState(),setState 方法接收 2 个参数

第 1 个参数:对象或者回调函数 是 1 个对象:对象内属性名 就是 构造函数 this.state 对象内的属性名
通过修改属性值,可以修改 this.state 对象内属性值,并更新视图和触发 render() 函数,例如:this.setState({
num: this.state.num + 1 }) 是回调函数:回调函数,接收 2 个参数 第 1 个参数:state
状态对象(存储的数据) 第 2 个参数:props 属性对象(父类通过属性传递的值存在 props 对象内) 回调函数内 return
一个的对象,对象属性名为 state 需要修改的属性名,例如:return { n: prevState.n + 1 }

第 2 个参数:是 1 个回调函数,数据更新完成后触发该函数,例如:this.setState({ num: this.state.num + 1 },()=>{console.log(‘数据更新完成后触发该函数’);})

注意:
更改 state 的值,不能直接改,直接更改视图不会同步,要更改 state 用 setState 更改
连续执行多次 this.setState() 函数会执行最后一个 this.setState()
this.setState() 是异步函数,先执行同步代码后执行,this.setState(),因此要得到执行完 setState 后的值,需要在第 2 个参数,回调函数内获取
组件内,事件函数没有 this ,需要通过 bind 绑定 render 内 this,并可以通过 bind 传值

setState() 第 1 个参数是 对象


  • state 状态:存储数据
    构造函数内设置 this.state 属性,是一个对象,可以存储数据,例如:this.state = { num: 0 };
  • setState 设置状态:修改数据
    setState 是一个函数,需要调用,可以操作构造函数 this.state 对象内的属性,并且跟新视图,且会触发 render 函数
    调用 setState 方法,通过 this.setState(),setState 方法接收 2 个参数

第 1 个参数:对象或者回调函数 是 1 个对象:对象内属性名 就是 构造函数 this.state 对象内的属性名
通过修改属性值,可以修改 this.state 对象内属性值,并更新视图和触发 render() 函数,例如:this.setState({
num: this.state.num + 1 }) 第 2 个参数:是 1
个回调函数,数据更新完成后触发该函数,例如:this.setState({ num: this.state.num + 1
},()=>{console.log(‘数据更新完成后触发该函数’);})

实例说明

  • 构造函数内设置 this.state{num:1}
  • 组件挂载完成后更改 state 内的值 this.setState({ num: this.state.num + 1 })
  • 渲染效果为 2
<div id="app"></div>

<script type="text/babel">

    class App extends React.Component {
     
     
        constructor(props) {
     
      // 1 先初始化
            super(props);
            
            // super() 传 props 与 this.props=props; 等价的
            // 父组件也是做的这个事 this.props=props;
            // 执行 super() 只是继承了父组件的实例化属性和方法
            // this.props=props;
            
            // state 存储数据
            this.state = {
     
     
                num: 1
            }
        }

        componentDidMount() {
     
      // 3 渲染完成触发
            // 改值后自动触发 render
            this.setState({
     
      // 连续执行多次 this.setState() 函数会执行最后一个 this.setState()
                num: this.state.num + 1
            }, () => {
     
     
                console.log('数据更新完成后触发')
            })
        }

        render() {
     
      // 2 渲染
            return (
                <div>
                    {
     
     this.state.num}{
     
     /* 渲染 2 */}
                </div>
            )
        }
    }

    ReactDOM.render(<App/>, document.querySelector('#app'));
</script>

猜你喜欢

转载自blog.csdn.net/weixin_45757442/article/details/104645731