最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Updating deeply nested state with useState not working properly - Stack Overflow

programmeradmin1浏览0评论

I followed the answer in this thread to try to update my deeply nested object in React. React: Setting State for Deeply Nested Objects w/ Hooks

What seems to work like a charm there, will somehow break for me when doing the following:

I have a table populated with items from an array defined like so:

const [items, setItems] = useState([
{
  selected: false,
  title: 'Item 1',
  status: 'new'
},
{
  selected: false,
  title: 'Item 2',
  status: 'used'
},
]);

When selecting an item from that list this function gets called to update selected variable for the object with the index i like so:

const select = (e) => {
  const i = e.target.getAttribute('data-index');
  setItems((prevState) => {
    prevState[i].selected = !prevState[i].selected;
    return [...prevState];
  });
};

This will work exactly once. If I trigger select a second time or any time after that return [...prevState] somehow keeps returning the state unchanged. (selected stays true forever). I can't solve this.

items is attached to a ponent List like so:

<List
   items={items}
/>

and inside List (shortened code):

{items.map((item, i) => {
      return (
        <tr className="list-table-tr">
          {hasSelector ? (
            <td className="list-table-td-selector">
              {item.selected ? (
                <div
                  data-index={i}
                  className="global-selector-selected"
                  onClick={select}
                ></div>
              ) : (
                <div
                  data-index={i}
                  className="global-selector-unselected"
                  onClick={select}
                ></div>
              )}
            </td>
          ) : null}

I followed the answer in this thread to try to update my deeply nested object in React. React: Setting State for Deeply Nested Objects w/ Hooks

What seems to work like a charm there, will somehow break for me when doing the following:

I have a table populated with items from an array defined like so:

const [items, setItems] = useState([
{
  selected: false,
  title: 'Item 1',
  status: 'new'
},
{
  selected: false,
  title: 'Item 2',
  status: 'used'
},
]);

When selecting an item from that list this function gets called to update selected variable for the object with the index i like so:

const select = (e) => {
  const i = e.target.getAttribute('data-index');
  setItems((prevState) => {
    prevState[i].selected = !prevState[i].selected;
    return [...prevState];
  });
};

This will work exactly once. If I trigger select a second time or any time after that return [...prevState] somehow keeps returning the state unchanged. (selected stays true forever). I can't solve this.

items is attached to a ponent List like so:

<List
   items={items}
/>

and inside List (shortened code):

{items.map((item, i) => {
      return (
        <tr className="list-table-tr">
          {hasSelector ? (
            <td className="list-table-td-selector">
              {item.selected ? (
                <div
                  data-index={i}
                  className="global-selector-selected"
                  onClick={select}
                ></div>
              ) : (
                <div
                  data-index={i}
                  className="global-selector-unselected"
                  onClick={select}
                ></div>
              )}
            </td>
          ) : null}
Share Improve this question edited Sep 21, 2021 at 14:52 smac89 43.3k15 gold badges150 silver badges198 bronze badges asked Sep 21, 2021 at 14:39 DawesignDawesign 7732 gold badges7 silver badges28 bronze badges 1
  • There has to be a good dupetarget for this. Anyone have one? – T.J. Crowder Commented Sep 21, 2021 at 14:46
Add a ment  | 

1 Answer 1

Reset to default 9

You're breaking one of the primary rules of React state: You're modifying a state object directly, rather than making a copy.

To correctly do the update, you'd do this:

const select = (e) => {
    const i = e.target.getAttribute('data-index');
    setItems((prevState) => {
        // Copy the array (your code was doing that)
        const update = [...prevState];
        const item = update[i];
        // Copy the object (your code wasn't doing that) and update its
        // `selected` property
        update[i] = {...item, selected: !item.selected};
        return update;
    });
};

Note how both the array and the object are copied, rather than just the array.

发布评论

评论列表(0)

  1. 暂无评论