2017-02-06 7 views
3

Мой код работает, но у меня есть вопрос с наилучшей практикой: у меня есть массив объектов в состоянии, и взаимодействие с пользователем изменяет значение одного объекта за раз. Насколько я знаю, я не должен напрямую менять состояние, я всегда должен использовать setState. Если я хочу избежать этого с любой ценой, я буду глубоко клонировать массив по итерации и изменять клон. Затем установите состояние в клон. По-моему, избежать изменения состояния, которое я буду менять позже, просто снижает мою производительность.React - Изменение состояния без использования setState: нужно избегать этого?

Подробной версия: this.state.data представляет собой массив объектов. Он представляет список тем на форуме, а кнопка «Избранное» переключается, вызывая 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: Это скопирует указатель на массив и толчке(), сдвиг(), и т.д. изменяет состояние непосредственно. Будут затронуты как data, так и this.state.data.

var data = this.state.data.slice(0): Это делает мелкий клон, нажатие и сдвиг не изменяет состояние, но в моем клоне у меня все еще есть указатели на элементы массива состояния. Поэтому, если я изменю data[0].is_collected, также будет изменен this.state.data[0].is_collected. Это происходит до того, как я позвоню setState().

Обычно я должен сделать:

var data = []; 
for (var i in this.state.data) { 
    data.push(this.state.data[i]); 
} 

Затем изменить значение по индексу, установив его истинным, когда оно ложно или ложным, когда это правда:

data[index].is_collected = !data[index].is_collected; 

И изменение состояния:

this.setState({data: data}); 

Рассмотрим мой массив является относительно большим или чрезвычайно большим, я думаю, эта итерация уменьшит производительность моего APP. Я заплатил бы эту стоимость, если бы знал, что это правильный путь по любой причине. Однако в этой функции (clickCollect) я всегда устанавливаю новое значение в состояние, я не жду ложного ответа API, который бы сказал, чтобы прекратить внесение изменений. Во всех случаях новое значение переходит в состояние. Практически я звоню setState только для того, чтобы пользовательский интерфейс снова отображался. Так что вопросы:

  1. Должен ли я создать глубокий клон в этом случае? (for var i in ...)
  2. Если нет, имеет смысл сделать мелкий клон (.slice(0)), если в моем массиве содержатся объекты? Изменения происходят над объектами внутри массива, поэтому мелкий клон все еще меняет свое состояние, как и копия (data = this.state.data).

Мой код упрощен, а вызовы API вырезаны для простоты.

Это вопрос новичка, поэтому также возможен и совершенно другой подход. Или ссылки на другие Q & A.

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; 
+0

Спасибо всем за ваши ответы. Я не могу на самом деле «принять» одну из них, поскольку все четыре поставили некоторые проблемы с проблемой с разных точек зрения. Тем не менее, @CodinCat получает согласие, чтобы четко сформулировать свой ответ.Особая благодарность VJAI, Kelvin De Moya и Degr. –

ответ

0

Лично я не всегда следую правилу, если вы действительно понимаете, что вы пытаетесь сделать, тогда я не думаю, что это проблема.

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` 

Если вы действительно обеспокоены этим, просто пойти на immutable.js

0

приглушение государство непосредственно нарушает основной принцип РЕАКТ потока данных (который выполнен однонаправленные), что делает ваше приложение очень хрупкими и в основном игнорирует все жизненный цикл компонента.

Итак, в то время как ничто не останавливает вас от мутирования состояния компонента без setState ({}), вам придется избегать этого любой ценой, если вы действительно хотите воспользоваться React, иначе вы бы перескочили одну из основные функциональные возможности библиотеки.

0

Если я понял ваш вопрос правильно, у вас есть массив объектов и когда свойство одного объекта в изменении массива,

  1. Создать глубокий клон массива и перейти к SetState
  2. Создать неглубокий клон и перейти к SetState

Я только что проверил с reduxsample todo app, и в случае единственного свойства изменения объекта вы должны создать новую копию этого единственного объекта, а не весь массив. Я рекомендую вам прочитать о redux и, если возможно, использовать для управления состоянием вашего приложения.

0

Если вы хотите следовать рекомендациям лучших рекомендаций, вы должны сделать неглубокую копию всего массива при изменении любого свойства. Пожалуйста, изучите реализацию «неизменной» библиотеки.

Но, по моему опыту, и, на мой взгляд, следует называть метод setState, если у вас есть реализации «shouldCompomenentUpdate». Если вы думаете, что ваша мелкая копия будет потреблять гораздо больше ресурсов, а затем отреагируйте на виртуальные купольные проверки, вы можете сделать это:

this.state.data[0].property = !this.state.data[0].property; 
this.forceUpdate();