React-изменение состояния без использования setState: должно избегать его?
мой код работает, но у меня есть вопрос лучшей практики: у меня есть массив объектов в состоянии, и взаимодействие с пользователем изменит значение одного объекта за раз. Насколько я знаю, я не должен изменять состояние напрямую, я всегда должен использовать setState
вместо. Если я хочу избежать этого любой ценой, я глубоко клонирую массив итерацией и изменю клон. Затем установите состояние клона. На мой взгляд, избегая менять состояние, которое я изменю позже в любом случае это просто снижает мою производительность.
Полная версия:
этот.государство.данные-это массив объектов. Он представляет собой список тем в форуме, и любимая кнопка будет переключаться, вызывая clickCollect()
.
Поскольку у меня есть массив в состоянии, когда я изменяю свойство is_collected одного элемента, мне нужно создать копию массива для работы, и после изменения на новое значение я могу установить его в состояние.
var data = this.state.data.slice(0); data[index].is_collected = !data[index].is_collected; this.setState({data: data});
var data = this.state.data
: Это скопирует указатель на массив и push(), shift () и т. д. изменит состояние напрямую. Оба!--8--> и this.state.data
будут затронуты.
var data = this.state.data.slice(0)
: это делает мелкий клон, push и shift не изменяет состояние, но в моем клоне у меня все еще есть указатели на элементы массива состояния. Так что если я изменюсь data[0].is_collected
, this.state.data[0].is_collected
получает также изменен. Это происходит до того, как я звоню setState()
.
как правило, я do:
var data = []; for (var i in this.state.data) { data.push(this.state.data[i]); }
затем я изменяю значение в индексе, устанавливая его в true, когда это false или false, когда это true:
data[index].is_collected = !data[index].is_collected;
и изменения состояния:
this.setState({data: data});
считайте, что мой массив относительно большой или чрезвычайно большой, я думаю, что эта итерация уменьшит производительность моего приложения. Я бы заплатил эту цену, если бы знал, что это правильный путь по любой причине. Однако, в этой функции (clickCollect
) I всегда устанавливайте новое значение в состояние, я не жду ложного ответа API, который сказал бы, чтобы остановить внесение изменений. Во всех случаях новое значение будет входить в состояние. Практически я зову setState
только для UI, чтобы снова оказать. Итак, вопросы:
- должен ли я создать глубокий клон в этом случае? (
for var i in ...
) - если нет, имеет ли смысл сделать мелкий клон (
.slice(0)
), если мой массив содержит объекты? Изменения вносятся на объекты внутри массива, поэтому мелкий клон все еще изменяет мое состояние, как и копия (data = this.state.data
) будет делать.
мой код упрощен, а вызовы API вырезаны для простоты.
это вопрос новичка, поэтому также приветствуется совершенно другой подход. Или ссылки на другие Q & А.
import React from 'react'; var ForumList = React.createClass({ render: function() { return <div className="section-inner"> {this.state.data.map(this.eachBox)} </div> }, eachBox: function(box, i) { return <div key={i} className="box-door"> <div className={"favorite " + (box.is_collected ? "on" : "off")} onTouchStart={this.clickCollect.bind(null, i)}> {box.id} </div> </div> }, getInitialState: function() { return {data: [ { id: 47, is_collected: false }, { id: 23, is_collected: false }, { id: 5, is_collected: true } ]}; }, clickCollect: function(index) { var data = this.state.data.slice(0); data[index].is_collected = !data[index].is_collected; this.setState({data: data}); } }); module.exports = ForumList;
4 ответов
лично я не всегда следую правилу, если вы действительно понимаете, что вы пытаетесь сделать, то я не думаю, что это проблема.
var data = this.state.data.slice(0);
data[index].is_collected = !data[index].is_collected;
this.setState({data: data});
в этом случае мутирующее состояние и вызов setState
снова, как это прекрасно
this.state.data[index].is_collected = !this.state.data[index].is_collected;
this.setState({data: this.state.data});
причина, по которой вы должны избегать мутирования своего состояния, заключается в том, что если у вас есть ссылка на this.state.data
, а вызов setState
несколько раз, вы можете потерять ваши данные:
const myData = this.state.data
myData[0] = 'foo'
this.setState({ data: myData })
// do something...
// ...
const someNewData = someFunc()
this.setState({ data: someNewData })
myData[1] = 'bar' // myData is still referencing to the old state
this.setState({ data: myData }) // you lose everything of `someNewData`
если вы действительно беспокоитесь об этом, просто пойдите для незыблемыми.js
Если вы хотите следовать рекомендациям react, вы должны сделать мелкую копию всего своего массива при изменении любого свойства. Пожалуйста, ознакомьтесь с реализацией" неизменяемой " библиотеки.
но, по моему опыту и по моему мнению, setState
метод должен вызываться, если у вас есть реализации" shouldCompomenentUpdate". Если вы думаете, что ваша мелкая копия будет потреблять гораздо больше ресурсов, то реагируйте на виртуальные проверки dom, вы можете сделать это:
this.state.data[0].property = !this.state.data[0].property;
this.forceUpdate();
приглушение состояния напрямую нарушает основной принцип потока данных React (который должен быть однонаправленным), что делает ваше приложение очень хрупким и в основном игнорирует весь жизненный цикл компонента.
таким образом, хотя ничто не мешает вам мутировать состояние компонента без setState ({}), вам придется избегать этого любой ценой, если вы хотите действительно воспользоваться React, иначе вы будете перепрыгивать одну из основных функций библиотеки.
Если я правильно понял ваш вопрос, у вас есть массив объектов и когда свойство одного объекта в массиве изменяется,
- создайте глубокий клон массива и перейдите в setState
- создайте неглубокий клон и перейдите в setState
Я только что проверил с redux
пример приложения todo и в случае изменения одного свойства объекта вы должны создать новую копию этого одного объект не весь массив. Я рекомендую вам прочитать о redux
и по возможности использовать для управления состоянием вашего приложения.