【问题标题】:updating state using hooks in array of objects使用对象数组中的钩子更新状态
【发布时间】:2020-08-14 23:06:14
【问题描述】:

我想在我的对象中将 active 更改为 true,在控制台日志中我有状态的更新版本但是我无法更新状态本身,我觉得我这样做是错误的。任何帮助都会非常感谢你,肯定在某个地方有类似的帖子,但我什么都没找到。

const [components, setComponents] = useState([
  {
    compName: "Weather",
    path: 'weather',
    active: false
  },
  {
    compName: "Tasks",
    path: 'tasks',
    active: false
  },
])
                                                      

 function onActivateHandler(){
      setComponents((prevComponents) => {
        const copy = [...prevComponents]
        let newState = {...copy[1]}
        newState.active = true
        console.log(newState)
    
        return  {...prevComponents}
      })
 }

【问题讨论】:

    标签: javascript reactjs react-hooks state


    【解决方案1】:

    您只需将克隆的、修改后的对象与prevComponents 的其余部分一起返回。目前你只返回旧状态,所以什么都不会改变(除了你不小心返回了一个对象,而不是一个数组)。

    编辑:现在看起来不太漂亮,但它很安全。

    function onActivateHandler(){
        setComponents((prevComponents) => {
          const copy = [...s];
          const newState = {...copy.splice(1, 1)[0]}
          newState.active = true;
          return [...copy, newState];
        })
     }
    

    【讨论】:

    • 好的,谢谢,所以这行得通,只是每次都会导致状态重复,而不是替换旧状态..
    • 对,我忘了你必须把它拼接起来。只是一分钟。
    【解决方案2】:

    我认为你只需要为整个数组生成一个新的引用。

    我注意到的另一件事是您正在从您的 setComponents() 函数返回一个对象。由于状态变量components是一个数组,我认为你需要返回一个数组。

    另外,将onActivateHandler() 方法编写为箭头函数以将其绑定到组件上下文,以防万一,通常是您想要做的。

    我会这样写(我只是切换活动值来演示):

    const myComponent = () => {
        const [components, setComponents] = useState([
            {
               compName: "Weather",
               path: "weather",
               active: false,
            },
            {
               compName: "Tasks",
               path: "tasks",
               active: false,
            },
        ]);
    
        const onActivateHandler = () => {
            setComponents((prevComponents) => {
               // update the array reference
               const newState = [...prevComponents];
               newState[1].active = !newState[1].active;
    
               // Your state variable is an array,
               // so you need to return an array
               return [...prevComponents];
            });
        };
    
        return (
            <>
                <button onClick={onActivateHandler}>Click</button>
                <div>{components[1].active ? 'active' : 'inactive'}</div>
            </>
        )
    };
    

    正如lawrence-witt 所说,在某些情况下,不在新数组中创建新对象可能会导致不重新渲染,但在您的简单情况下,上面的代码工作正常,因为数组引用是 react 正在跟踪的,而不是内部对象的引用。如果需要,您可以将newState[1] 传播到一个新对象中,但您需要从状态数组中删除旧的对象。

    干杯!

    【讨论】:

    • 这不是一个好主意,因为如果不克隆对象,您将保留它的引用并在设置它之前改变状态。这通常会导致不会触发重新渲染。
    • 不,当然,我知道这一点。我只是明白 react 跟踪的引用是数组的引用。但我可能是错的。如有必要,我将对其进行测试和编辑。
    • 这里的危险不仅在于 React 不会对返回的状态进行适当的相等性检查并重新渲染该组件,而且任何将 components[1].active 作为道具的子组件都会表现出意外当该值过早突变时的方式。我建议在修改任何 React 状态时解耦引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 2021-08-29
    相关资源
    最近更新 更多