Modificação correta de matrizes de estado no ReactJS

Eu quero adicionar um elemento ao final de uma matriz de state , esta é a maneira correta de fazê-lo?

 this.state.arrayvar.push(newelement); this.setState({arrayvar:this.state.arrayvar}); 

Preocupa-me que modificar o array in-place com push possa causar problemas – é seguro?

A alternativa de fazer uma cópia da matriz e setState isso parece um desperdício.

A documentação do React diz:

Trate this.state como se fosse imutável.

Seu push sofrerá a mutação do estado diretamente e poderá levar a um código propenso a erros, mesmo que você esteja “redefinindo” o estado novamente depois disso. F.ex, isso pode levar a que alguns methods do ciclo de vida, como componentDidUpdate , não sejam acionados.

A abordagem recomendada nas versões posteriores do React é usar uma function atualizadora ao modificar estados para evitar condições de corrida:

 this.setState(prevState => ({ arrayvar: [...prevState.arrayvar, newelement] })) 

A memory “desperdício” não é um problema em comparação com os erros que você pode enfrentar usando modificações de estado não padrão.

Sintaxe alternativa para versões anteriores do React

Você pode usar concat para obter uma syntax limpa, pois ela retorna uma nova matriz:

 this.setState({ arrayvar: this.state.arrayvar.concat([newelement]) }) 

No ES6, você pode usar o Operador de propagação :

 this.setState({ arrayvar: [...this.state.arrayvar, newelement] }) 

Mais fácil, se você estiver usando o ES6 .

 initialArray = [1, 2, 3]; newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4] 

Nova matriz será [1,2,3,4]

para atualizar seu estado em React

 this.setState({arrayvar:[...this.state.arrayvar, newelement]}); 

Saiba mais sobre a desestruturação de matrizes

A maneira mais simples com o ES6 :

 this.setState(prevState => ({ array: [...prevState.array, newElement] })) 

Reagir pode atualizações em lote e, portanto, a abordagem correta é fornecer setState com uma function que executa a atualização.

Para o addon de atualização do React, o seguinte funcionará de forma confiável:

 this.setState( (state) => update(state, {array: {$push: [4]}}) ); 

ou para concat ():

 this.setState( (state) => { state.array = state.array.concat([4]); return state; }); 

As informações a seguir mostram o que https://jsbin.com/mofekakuqi/7/edit?js , mostra como um exemplo do que acontece se você errar.

A invocação setTimeout () adiciona corretamente três itens porque o React não atualizará em lote dentro de um retorno de chamada setTimeout (consulte https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ ).

O buggy onClick só adicionará “Terceiro”, mas o fixo adicionará F, S e T como esperado.

 class List extends React.Component { constructor(props) { super(props); this.state = { array: [] } setTimeout(this.addSome, 500); } addSome = () => { this.setState( update(this.state, {array: {$push: ["First"]}})); this.setState( update(this.state, {array: {$push: ["Second"]}})); this.setState( update(this.state, {array: {$push: ["Third"]}})); }; addSomeFixed = () => { this.setState( (state) => update(state, {array: {$push: ["F"]}})); this.setState( (state) => update(state, {array: {$push: ["S"]}})); this.setState( (state) => update(state, {array: {$push: ["T"]}})); }; render() { const list = this.state.array.map((item, i) => { return 
  • {item}
  • }); console.log(this.state); return (
      {list}
    ); } }; ReactDOM.render(, document.getElementById('app'));

    Como @nilgun mencionado no comentário, você pode usar os auxiliares de imutabilidade reacionados. Eu achei isso muito útil.

    Dos docs:

    Impulso simples

     var initialArray = [1, 2, 3]; var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] 

    initialArray ainda é [1, 2, 3].