Eu tenho o seguinte estado:
this.setState({ selected: { id: 1, name: 'Foobar' } });
Então eu atualizo o estado:
this.setState({ selected: { name: 'Barfoo' }});
Como setState
é suposto fundir, eu esperaria que fosse:
{ selected: { id: 1, name: 'Barfoo' } };
Mas, em vez disso, ele come o id e o estado é:
{ selected: { name: 'Barfoo' } };
Esse comportamento é esperado e qual é a solução para atualizar apenas uma propriedade de um objeto de estado aninhado?
javascript
reactjs
Pickels
fonte
fonte
this.setState({ selected: { ...this.state.selected, name: 'barfoo' } })
que é traduzida parathis.setState({ selected: _extends({}, this.state.selected, { name: 'barfoo' }) });
underscore
/lodash
. Gire em sua própria resposta, por favor.this.state
não é necessariamente atualizado . Você pode obter resultados inesperados usando o método extend. Passar uma função de atualização parasetState
é a solução correta.Os auxiliares de imutabilidade foram adicionados recentemente ao React.addons, portanto, com isso, agora você pode fazer algo como:
Documentação dos auxiliares de imutabilidade .
fonte
React.addons.update()
método está obsoleto, mas a biblioteca de substituição github.com/kolodny/immutability-helper contém umaupdate()
função equivalente .Como muitas das respostas usam o estado atual como base para mesclar novos dados, eu queria ressaltar que isso pode quebrar. As alterações de estado estão na fila e não modificam imediatamente o objeto de estado de um componente. A referência aos dados do estado antes do processamento da fila fornecerá dados obsoletos que não refletem as alterações pendentes que você fez no setState. Dos documentos:
Isso significa que o uso do estado "atual" como referência nas chamadas subsequentes para setState não é confiável. Por exemplo:
Se você precisar usar o estado atual (por exemplo, para mesclar dados em um objeto aninhado), setState aceitará uma função como argumento em vez de objeto; a função é chamada após qualquer atualização anterior do estado e passa o estado como argumento - portanto, isso pode ser usado para fazer alterações atômicas garantidas para respeitar as alterações anteriores.
fonte
this.state
, que pode ser obsoleto (ou melhor, atualização em fila pendente) quando você acessá-lo.Eu não queria instalar outra biblioteca, então aqui está outra solução.
Ao invés de:
Faça isso:
Ou, graças a @ icc97 nos comentários, ainda mais sucintamente, mas sem dúvida menos legível:
Além disso, para esclarecer, essa resposta não viola nenhuma das preocupações mencionadas acima pelo @bgannonpl.
fonte
this.setState({ selected: Object.assign(this.state.selected, { name: "Barfoo" }));
Object.assign(a, b)
recebe atributosb
, insere / substitui-osa
e depois retornaa
. Reagir as pessoas ficam chateadas se você modificar o estado diretamente.{}
como o primeiro argumento:this.setState({ selected: Object.assign({}, this.state.selected, { name: "Barfoo" }) });
. Isso não altera o estado original.Preservando o estado anterior com base na resposta @bgannonpl:
Exemplo de Lodash :
Para verificar se funcionou corretamente, você pode usar o segundo retorno de chamada da função de parâmetro:
Eu usei
merge
porqueextend
descarta as outras propriedades de outra forma.Exemplo de React Immutability :
fonte
Minha solução para esse tipo de situação é usar, como outra resposta apontada, os auxiliares da Imutabilidade .
Como definir o estado em profundidade é uma situação comum, criei o seguinte mixin:
Esse mixin está incluído na maioria dos meus componentes e geralmente não uso
setState
mais diretamente.Com este mixin, tudo o que você precisa fazer para obter o efeito desejado é chamar a função
setStateinDepth
da seguinte maneira:Para maiores informações:
setStateinDepth
ver a documentação dos Auxiliares da Imutabilidade .fonte
this.state.test.two
ainda estará lá depois que você atualizarthis.state.test.one
usandosetStateInDepth({test: {one: {$set: 'new-value'}}})
. Eu uso esse código em todos os meus componentes para contornar asetState
função limitada do React .this.state.test
como uma matriz. Mudando para Objetos, resolvi-o.Estou usando classes es6 e acabei com vários objetos complexos no meu estado superior e estava tentando tornar meu componente principal mais modular. Por isso, criei um invólucro de classe simples para manter o estado no componente superior, mas permitir uma lógica mais local .
A classe wrapper assume uma função como seu construtor que define uma propriedade no estado do componente principal.
Em seguida, para cada propriedade complexa no estado superior, crio uma classe StateWrapped. Você pode definir os props padrão no construtor aqui e eles serão definidos quando a classe for inicializada; você poderá consultar o estado local para obter valores e definir o estado local, consultar funções locais e passar a cadeia:
Portanto, meu componente de nível superior precisa apenas do construtor para definir cada classe como sua propriedade de estado de nível superior, uma renderização simples e quaisquer funções que se comuniquem entre componentes.
Parece funcionar muito bem para meus propósitos, lembre-se de que você não pode alterar o estado das propriedades que atribui aos componentes agrupados no componente de nível superior, pois cada componente agrupado está acompanhando seu próprio estado, mas atualizando o estado no componente superior cada vez que muda.
fonte
A partir de agora,
de acordo com a documentação https://reactjs.org/docs/react-component.html#setstate , usando:
fonte
Solução
Edit: Esta solução costumava usar sintaxe de propagação . O objetivo era criar um objeto sem referências
prevState
, para queprevState
não fosse modificado. Mas no meu uso,prevState
às vezes parecia ser modificado. Portanto, para uma clonagem perfeita sem efeitos colaterais, agora convertemosprevState
para JSON e depois novamente. (A inspiração para usar o JSON veio do MDN .)Lembrar:
setState(prevState => stateChange)
Passos
state
que deseja mudançaOs passos 3 e 4 podem ser combinados em uma linha.
Exemplo
Exemplo simplificado:
Isso segue bem as diretrizes do React. Baseado na resposta de eicksl a uma pergunta semelhante.
fonte
Solução ES6
Definimos o estado inicialmente
Estamos alterando uma propriedade em algum nível do objeto state:
fonte
O estado de reação não executa a mesclagem recursiva
setState
enquanto espera que não haja atualizações de membro de estado no local ao mesmo tempo. Você precisa copiar objetos / matrizes fechados (com array.slice ou Object.assign) ou usar a biblioteca dedicada.Como este. O NestedLink suporta diretamente o manuseio do estado React composto.
Além disso, o link para o
selected
ouselected.name
pode ser transmitido para qualquer lugar como um único suporte e modificado com eleset
.fonte
você definiu o estado inicial?
Vou usar um pouco do meu próprio código, por exemplo:
Em um aplicativo em que estou trabalhando, é assim que tenho definido e usado o estado. Acredito que
setState
você pode editar qualquer estado que desejar individualmente.Lembre-se de que você deve definir o estado na
React.createClass
função que você chamougetInitialState
fonte
Eu uso o tmp var para mudar.
fonte
let original = {a:1}; let tmp = original; tmp.a = 5; // original is now === Object {a: 5}
Não faça isso, mesmo que isso ainda não tenha lhe causado problemas.