React Hooks - useState

1,251 阅读3分钟

useState

在 React 16.8 版本之前,函数组件被用于编写 简单的 UI 组件和无状态组件。如果需要在函数组件中使用状态,就需要将其转换为类组件,这增加了代码复杂度,同时也不便于代码的维护。因此,React 团队引入了 Hook 机制,使得函数组件也可以方便地使用状态、生命周期等特性。

  • 函数组件也是一个普通函数,函数执行完就会被销毁了,那么自然它的状态也就没法保存只有返回值。为了让函数组件有自己的状态(指的时你声明的响应式变量) React 引入了 Hook 使得你的状态可以存留在函数里。当函数里面的值被引用时那么它就会形成一个闭包。所以说函数组件就是一个闭包。

useState 的使用

调用 useState 方法,传入一个初始值, 返回的一个数组。

语法:

const [state, setState] = useState(initialState);
  • initialState:状态的初始值(也可以是一个函数下面演示)。
  • state:初始值响应式状态。
  • setState:用于更新状态的函数,每次调用它都会重新渲染组件。

在函数组件中改变状态时使用 set(setState)方法有两种形式 直接更新函数式更新

直接更新 和 函数式更新

import React, { useState } from "react";
const [state, setState] = useState(0);

export default const App = ()=>{

    // 直接更新
    function handleClick() {
       /**
        * state = 5
        * 直接赋值 并不会更新
        * */
       setState(count + 1);
    }

    // 函数式更新 set 方法接收一个函数
    function handleClickFn() {
       setState((prevState) => {
          // prevCount上一次 state 最新的值
          return prevState + 1;
       });
    }

    return (
       <div>
          State: {State}
          <button onClick={handleClick}>直接更新</button>
          <button onClick={handleClickFn}>函数式更新</button>
       </div>
    );

}

  • 直接更新 set 方法直接传入需要更新的值就行
  • 函数式更新 set 方法接受一个函数,这个函数的返回值就是需要更新的值

划重点:

函数组件中 你直接修改 响应式状态的值(state)并不会更新,必须调用它对应的 set 方法才可以刷新视图

直接更新 与 函数式更新 的使用场景

  • 当我们加一个定时器就能看出他们两的不同了
import React, { useState } from "react";

export default const App = ()=>{

    // useStaet 初始值接受一个参数
     function getState() {
         let a = 1
         let b = 1
         return a + b;
     }

    const [state, setState] = useState(getState);

    // 直接更新
     function handleClick() {
         console.log("直接更新");
         setTimeout(() => {
             setState(state + 1)
         }, 2000);
     }

    // 函数式更新
     function handleClickFn() {
         console.log("函数式更新");
         setTimeout(() => {
             setState((prevState) => {
                 return prevState + 1
             })
         }, 2000);

     }

     return (
         <div>
             state: {state}
               <br />
               <button onClick={handleClick}>直接更新</button>
               <button onClick={handleClickFn}>函数式更新</button>
         </div>
     );
};

上面代码执行效果:

6F.gif

在图中 两种更新方式都点击了 5 次, 理想状态下 state 的值 2+5 应该是 7。但是 直接更新 state 的值停留在了 3 ,只有 函数式更新 的值才是正确的。

这是因为....

函数式更新

set 接收一个函数,这个函数接收一个参数(prevState),这个参数的返回值永远是上一次最新的值,因为函数式更新会将这次更新的值依次传递给下一次的函数式更新,所以这里得到的值是最新的。

直接更新

每一次更新都是一个闭包(函数式更新也是)先记住这个。当我们快速点击时创建 5 个定时器,注意这个定时器时在 state 为 2 的闭包中时候创建的,所以此时它 5 个定时器 中 set 接收的参数都是 state + 1 也是 3,它并不会像函数式更新一样依次传递下去 。5 次更新都是 3 ,React 会进行浅比较所以相当于只更新了一次

总结:

  • 直接更新: 直接传入新的 state 值即可。适用于与返回的新值与旧值不存在依赖关系

  • 函数式更新:传入一个函数 用该函数的返回值进行更新。适合用于旧值和新值有关系

最后

如果你对浅比较不太理解或者想深入一下 useSstate 可以看一下我上一篇的文章