应该使用单个还是多个 state 变量?

f84f36bf9544f5ae2f0da0d6709a8611.png

如果你之前用过 class,你或许会试图总是在一次 useState() 调用中传入一个包含了所有 state 的对象。如果你愿意的话你可以这么做。这里有一个跟踪鼠标移动的组件的例子。我们在本地 state 中记录它的位置和尺寸:

function Box() {
  const [state, setState] = useState({ left: 0, top: 0, width: 100, height: 100 });
  // ...
}

现在假设我们想要编写一些逻辑以便在用户移动鼠标时改变 left 和 top。注意到我们是如何必须手动把这些字段合并到之前的 state 对象的:

// ...
  useEffect(() => {
    function handleWindowMouseMove(e) {
      // 展开 「...state」 以确保我们没有 「丢失」 width 和 height
      setState(state => ({ ...state, left: e.pageX, top: e.pageY }));
    }
    // 注意:这是个简化版的实现
    window.addEventListener('mousemove', handleWindowMouseMove);
    return () => window.removeEventListener('mousemove', handleWindowMouseMove);
  }, []);
// ...

这是因为当我们更新一个 state 变量,我们会 替换 它的值。这和 class 中的 this.setState 不一样,后者会把更新后的字段 合并 入对象中。

如果你还怀念自动合并,你可以写一个自定义的 useLegacyState Hook 来合并对象 state 的更新。

import { useState, useEffect } from "react";


function useLegacyState(initialState) {
  const [state, setState] = useState(initialState);


  useEffect(() => {
    setState(prevState => {
      return { ...prevState, ...state };
    });
  }, [state]);


  return [state, setState];
}

然而,我们推荐把 state 切分成多个 state 变量,每个变量包含的不同值会在同时发生变化。

举个例子,我们可以把组件的 state 拆分为 position 和 size 两个对象,并永远以非合并的方式去替换 position:

function Box() {
  const [position, setPosition] = useState({ left: 0, top: 0 });
  const [size, setSize] = useState({ width: 100, height: 100 });


  useEffect(() => {
    function handleWindowMouseMove(e) {
      setPosition({ left: e.pageX, top: e.pageY });
    }
    // ...

把独立的 state 变量拆分开还有另外的好处。这使得后期把一些相关的逻辑抽取到一个自定义 Hook 变得容易,比如说:

function Box() {
  const position = useWindowPosition();
  const [size, setSize] = useState({ width: 100, height: 100 });
  // ...
}


function useWindowPosition() {
  const [position, setPosition] = useState({ left: 0, top: 0 });
  useEffect(() => {
    // ...
  }, []);
  return position;
}

注意看我们是如何做到不改动代码就把对 position 这个 state 变量的 useState 调用和相关的 effect 移动到一个自定义 Hook 的。如果所有的 state 都存在同一个对象中,想要抽取出来就比较难了。

把所有 state 都放在同一个 useState 调用中,或是每一个字段都对应一个 useState 调用,这两方式都能跑通。当你在这两个极端之间找到平衡,然后把相关 state 组合到几个独立的 state 变量时,组件就会更加的可读。如果 state 的逻辑开始变得复杂,我们推荐 用 reducer 来管理它,或使用自定义 Hook。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值