【问题标题】:I can't properly change the boolean of an array with prevState我无法使用 prevState 正确更改数组的布尔值
【发布时间】:2021-09-30 07:15:25
【问题描述】:

感谢大家尝试回答我之前的问题。我刚刚学会了如何在我的数组对象中改变布尔值。

现在我需要触发重新渲染,因为我的对象发生了变化,但对生命周期了解不多。我是新手,所以有点手将是完美的。谢谢各位。

  export default function App() {
      const [obj, setObj] = useState([
        { name: "chicken", comments: "nice", photo: img, boolean: false },
        { name: "beef", comments: "ehh", photo: img, boolean: false },
        { name: "turkey", comments: "not bad", photo: img,  boolean: false },
        { name: "broccoli", comments: "cool", photo: img,  boolean: false },
        { name: "carrot", comments: "disgusting",photo: img, boolean: false }
      ]);
    
    const handleClick = (e) => {
      const idx = e.target.value;
      setObj(prev => {
    prev[idx].boolean = !prev[idx].boolean
    return prev
      });
      window.alert(JSON.stringify(obj)); 
    
      }
              return (
              <div>
              {obj.map((map, key) => (
                <div>
                  <img src={map.photo} alt={map.key} />
                  <h1>{map.name}</h1>
                  <p>{`${map.boolean}`}</p>
                  <p>{key}</p>
                  <button value={key} onClick={handleClick}>
                    show comments
                  </button>
                </div>
              ))}
            </div>
          );
    }

【问题讨论】:

  • 我已经更新了答案

标签: reactjs object setstate


【解决方案1】:

问题来了

setObj(prev => 
      [...prev, prev[idx].boolean = true]
)

您实际上是在推动另一个布尔值 像这样修改handleClick函数

const handleClick = (e) => {
    const idx = e.target.value;// getting the required idx
    const newObj = JSON.parse(JSON.stringify(obj)); // creating a new obj 
    obj[idx].boolean = true; // setting the newobj boolean value
    setObj(newObj); // useState function to set new state.
};

【讨论】:

    【解决方案2】:

    这就是所谓的destructuring assignment

    [...prev, prev[idx].boolean = true]
    

    你基本上说.. 嘿,拿这个对象,传播它的值,然后分配这个新值并附加它。问题在于您创建一个新变量prev[idx].boolean 没有分配一个新值。这就是问题的根源。

    现在,你应该做的是在外面创建这个变量

    const value = { ...prev[idx] }
    value.boolean = true
    

    您应该创建一个新对象,否则它会通过引用传递

    在传递引​​用中,通过直接传递变量的引用/地址作为参数来调用函数。更改函数内部的参数会影响从函数外部传递的变量。在 Javascript 中,对象和数组是通过引用传递的。

    然后赋值

    setObj(prev => 
      [...prev, value]
    )
    

    这意味着您将覆盖任何具有相同值的解构元素,或者如果它没有任何值,则只需分配新值。


    编辑

    问题是你正在改变状态变量

    setObj(prev => {
      prev[idx].boolean = !prev[idx].boolean
      return prev
    });
    

    改为这样做

    setObj(prev => {
      const value = { ...prev[idx] };
      value.boolean = !value.boolean;
      
      return [...prev, value];
    });
    

    或者这个

    const value = { ...prev[idx] };
    value.boolean = !value.boolean;
    
    setObj([...obj, value]);
    

    在我之前的回复中,我引用了 按引用传递.. 你应该仔细阅读它,因为你正在尝试创建一个对象的浅表副本,如果您也不关心更改原始对象。

    由于您尝试更改状态,因此您不能更改状态变量本身。这就是这里发生的事情

    prev[idx].boolean = !prev[idx].boolean
    return prev
    

    您必须创建一个新对象来触发重新渲染生命周期。

    【讨论】:

    • 这实际上对我有用。我可以改变内部的布尔值。但是,我的组件现在不会重新渲染。所以我无法显示我渲染项目的变化。有什么建议么?谢谢一百万。
    • 你能用新代码更新你的问题吗?
    【解决方案3】:

    多亏了评论者的贡献,我终于解决了这个问题。

    这就是问题所在。我试图改变状态,它是一个对象数组。我这样做是因为 prevstate 适用于字符串和整数类型的状态(例如,增加数字按钮。)但是,在改变对象和数组时情况会有所不同。

    如果你改变一个对象,react 不会重新渲染,因为扩展数组方法会创建一个浅拷贝。感谢 @kmp 和其他人帮助我解决这个问题。

    我必须创建一个数组的副本以进行变异,并让 react 知道状态已发生变异。错误的setStat 代码可以改变布尔值但不能重新渲染,在代码的底部被注释掉了。

    我从这个错误中学到了很多,我非常感谢做出贡献的人。干杯。

    export default function App() {
      const [obj, setObj] = useState([
        { name: "chicken", comments: "nice", photo: img, boolean: false },
        { name: "beef", comments: "ehh", photo: img, boolean: false },
        { name: "turkey", comments: "not bad", photo: img,  boolean: false },
        { name: "broccoli", comments: "cool", photo: img,  boolean: false },
        {
          name: "carrot",
          comments: "disgusting",
          photo: img,
          key: 4,
          boolean: false
        }
      ]);
    
      const handleClick = (e) => {
          const idx = e.target.value;
          const newObj = JSON.parse(JSON.stringify(obj)); 
          newObj[idx].boolean = !newObj[idx].boolean; 
          setObj(newObj);
      }
      return (
        <div className="main-div">
          {obj.map((map, key) => (
            <div className="child-div">
              <img src={map.photo} alt={map.key} />
              <h1>{map.name}</h1>
              <p>{map.boolean ? map.comments : null}</p>
              <button value={key} onClick={handleClick}>
              {map.boolean ? "hide comments" : "show comments"}
              </button>
            </div>
          ))}
        </div>
      );
    }
    
    /*
    const idx = e.target.value;
    setObj(prev => {
      prev[idx].boolean = !prev[idx].boolean;
      return prev;
    })
    
    window.alert(JSON.stringify(obj));
    */
    
    

    【讨论】:

      【解决方案4】:

      嗯,这实际上就是你在那里所做的,你正在传播一个数组并在之后添加一个项目!你能做什么:

      const handleClick = (e) => {
          const idx = e.target.value;
          setObj(prev => {
             prev[idx].boolean = true;
             return prev;
            } 
          )
          console.log(obj);
        };
      
      

      这很有可能奏效。

      同样对于这种巨大的状态,我建议你考虑useReducer from react。

      如果我想完成以上:

      export default function App() {
        const [obj, setObj] = useState([...]);
        const [update, setUpdate] = useState(false);
        const handleClick = (e) => {
          const idx = e.target.value;
          setObj(prev => {
             prev[idx].boolean = true;
             return prev;
            } 
          )
          setUpdate(prev => !prev);
        };
        return (
          <div className="main-div">
            {obj.map((map, key) => (
              <div className="child-div">
                <img src={map.photo} alt={map.key} />
                <h1>{map.name}</h1>
                <p>{map.boolean ? map.comments : null}</p>
                <button value={key} onClick={handleClick}>
                {map.boolean ? "hide comments" : "show comments"}
                </button>
              </div>
            ))}
          </div>
        );
      }
      

      这将使它工作。

      【讨论】:

      • 太棒了。这就是我要找的。我可以改变内部的布尔值。但是,我的组件现在不会重新渲染。所以我无法显示我渲染项目的变化。有什么建议么?谢谢一百万!
      • 当然,使用 react 'useReducer' 可以解决问题,你用过吗?你可以做一些事情,比如通过用另一个“useState”改变一个布尔值的状态来强制更新。类似于: [update, setUpdate] = useState(false) 并在 setObj 之后切换它
      猜你喜欢
      • 2019-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-20
      • 2018-02-19
      • 2020-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多