React: как изменить состояние на основе массива без индекса или уникального идентификатора?

#javascript #reactjs #immutability

#javascript #reactjs #неизменяемость

Вопрос:

Допустим, у меня есть компонент с вкладками. На каждой вкладке представлен объект person. Пользователь может переключать активную вкладку, изменять или удалять каждую из них и даже изменять их порядок:

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

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

    },
  ]
}
  

Допустим, я хочу изменить одно из полей определенной вкладки (person). У меня могла бы быть эта функция:

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

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

  const tab = tabs[index];

  tab[prop] = value;

  this.setState({ tabs })
}
  

Проблема с этим заключается в том, что оно зависит от индекса данной вкладки. Но что, если изменится индекс табуляции, если я предоставлю, скажем, возможность переключения порядка табуляции?(как браузеры делают для своих вкладок).

Или что, если мне нужно зарегистрировать некоторый обратный вызов для операции a-sync, которая может быть вызвана, когда соответствующий пользователь находится на другой вкладке (возможно, вкладка была перемещена с 1 на 0 к моменту обратного вызова)?

Есть ли какой-либо способ просто полагаться на ссылку на объект, независимо от идентификатора, индекса или любого другого «идентификатора», что делает код намного сложнее, чем он должен быть?

Для тех, кто знаком с VueJS и Angular, я уверен, вы знаете, как легко изменять объекты, поскольку вам не нужно возвращать новое дерево состояний при каждом изменении.

Комментарии:

1. Как насчет уникального идентификатора для каждого объекта? Затем отфильтруйте то, что вам нужно

2. В том-то и дело, есть ли способ не полагаться на идентификаторы? Должен ли я просто дать некоторый произвольный случайный идентификатор каждой вкладке? Игнорируйте тот факт, что вкладка представляет пользователей, у которых на самом деле могут быть идентификаторы. С таким же успехом это могло бы быть что-то другое.

3. Если вы меняете порядок массива, вы не можете полагаться на index for key prop при рендеринге. И да, передача всей ссылки на объект modifyTab была бы совершенно прекрасной. Вы могли бы выяснить, какой объект в массиве это с помощью простого indexOf .

4. Толле, это очень хорошая идея, я попробую это

5. Уникальный идентификатор был бы полезен, кроме того, вам может потребоваться сохранить пользователей в БД позже

Ответ №1:

Если вы меняете порядок массива, вы не можете полагаться на массив 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>