qual é a maneira preferida de transformar um estado de reação?

97

Digamos que eu tenha uma lista de objetos simples na minha this.state.listque posso usar para renderizar uma lista de filhos. Qual é então a maneira certa de inserir o objeto this.state.list?

Abaixo está a única maneira que acho que funcionará, porque você não pode alterar o this.statediretamente conforme mencionado no documento.

this._list.push(newObject):
this.setState({list: this._list});

Isso me parece feio. Existe uma maneira melhor?

Khoi
fonte
possível duplicata de modificação correta de matrizes de estado no ReactJS , solicitando fusão
Brigand
Todas essas respostas são sobre como adicionar um elemento a uma matriz. Mas que tal remover um elemento dele? Ou simplesmente redefinir completamente o array para um novo?
Augustin Riedinger

Respostas:

165

concat retorna uma nova matriz, então você pode fazer

this.setState({list: this.state.list.concat([newObject])});

outra alternativa é o auxiliar de imutabilidade do React

  var newState = React.addons.update(this.state, {
      list : {
        $push : [newObject]
      }
  });

  this.setState(newState);
Heap
fonte
6
concatpega um array, então você vai querer this.state.list.concat([newObject]).
Sophie Alpert
@BenAlpert funciona para mim no Chrome, você está dizendo que este é um comportamento fora do padrão?
Heap
6
@Heap Bem, se você passar um não-array para concatele irá envolvê-lo em um array, mas é melhor adicionar o array você mesmo para ser explícito: se você tem [[1,2], [3,4]]e deseja adicionar [5,6]como o próximo elemento, você precisa fazer .concat([[5,6]])outra coisa vai acabar com [[1,2], [3,4], 5, 6].
Sophie Alpert
2
Por mais que eu aprecie a ideia por trás dos ajudantes de imutabilidade (e posso acabar usando de qualquer maneira), com Array.concatcerteza é melhor adicionar outra biblioteca.
Shawn Erquhart
1
Chamar this.setState com um valor derivado de this.state fará com que você tenha problemas de atualização em lote. Consulte stackoverflow.com/a/41445812/1998186 que leva a um jsfiddle mostrando o problema que você encontrará.
NealeU
40

setState () pode ser chamado com uma função como parâmetro:

this.setState((state) => ({ list: state.list.concat(newObj) }))

ou em ES5:

this.setState(function(state) {
  return {
   list: state.list.concat(newObj)
  }
})
Nyalab
fonte
2
@Arian: React executará as instruções de mutação DOM necessárias para renderizar apenas os elementos recém-adicionados. Dado, é claro, que você adicionou elementos recentemente, não mudam a forma como os elementos anteriores eram renderizados.
Jose Browne
1
Esta é uma resposta fantástica e parece muito mais limpa do que concatenar array apenas para executar um push, embora essa seja a opinião, eu acho.
Matt Styles
2
@Nyalab você não deveria envolver o corpo da função entre parênteses? Como está agora em seu exemplo, os colchetes após a seta grande iniciariam um bloco, não um objeto. Algo assim:this.setState((state) => ({ list: state.list.push(newObj) }))
kumarharsh
3
Como esse código está funcionando? o método push retornará um NUMBER, que será definido na listvariável
kumarharsh
1
Você também pode usar um splat:this.setState((state) => ({ list: [...state.list, newObj] }))
amebe
19

Atualização 2016

Com ES6 você pode usar:

this.setState({ list: [...this.state.list, ...newObject] });
Ashish Chaudhary
fonte
5
...[newObject]é o mesmo que justo newObject.
amebe
2
Isso não funcionará para atualizações em lote. Veja meu exemplo em stackoverflow.com/a/41445812/1998186 .
NealeU