首页 > 解决方案 > React:如何在没有索引或唯一标识符的情况下修改基于数组的状态?

问题描述

假设我有一个选项卡式组件。每个选项卡都显示一个人员对象。用户可以切换活动选项卡,修改或删除每个选项卡,甚至更改其顺序:

state={
  activeTab:0,
  tabs:[
    {
      name:'John',
      age:34

    },
    {
      name:'Bob',
      age:31

    },
  ]
}

假设我想修改特定选项卡(人)的字段之一。我可以有这个功能:

modifyTab = (index, prop, value) => {

  const tabs = [...this.state.tabs];

  const tab = tabs[index];

  tab[prop] = value;

  this.setState({ tabs })
}

问题在于它依赖于给定选项卡的索引。但是如果标签索引发生变化,如果我提供,比如说,切换标签顺序的能力?(就像浏览器为他们的标签所做的那样)。

或者,如果我需要为异步操作注册一些回调,当相关人员坐在不同的选项卡中时可能会调用该回调(可能在调用回调时选项卡已从 1 移动到 0)?

有没有办法只依赖对象引用,而不考虑 id、index 或任何其他“标识符”,这使得代码比它需要的复杂得多?

对于那些熟悉 VueJS 和 Angular 的人,我相信你知道修改对象是多么容易,因为你不需要在每次更改时返回一个新的状态树。

标签: javascriptreactjsimmutability

解决方案


如果要更改数组的顺序,则在渲染时不能依赖数组index作为key道具。解决此问题的一种常见方法是为数组中的每个对象添加一个唯一属性并使用它来代替,例如id.

传入整个对象引用modifyTab就可以了。您可以通过简单的indexOf.

例子

class App extends React.Component {
  state = {
    tabs: [
      {
        name: "John",
        age: 34,
        id: 1
      },
      {
        name: "Bob",
        age: 31,
        id: 2
      }
    ]
  };

  modifyTab = (tab, prop, value) => {
    this.setState(prevState => {
      const tabs = [...prevState.tabs];
      const index = tabs.indexOf(tab);

      tabs[index] = { ...tabs[index], [prop]: value };

      return { tabs };
    });
  };

  render() {
    return (
      <div>
        {this.state.tabs.map(tab => (
          <span
            key={tab.id}
            onClick={() => this.modifyTab(tab, "name", Math.random())}
            style={{ margin: '0 10px' }}
          >
            {tab.name}
          </span>
        ))}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>


推荐阅读