#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
forkey
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>