Estou tentando organizar meu estado usando propriedades aninhadas como esta:
this.state = {
someProperty: {
flag:true
}
}
Mas atualizando o estado assim,
this.setState({ someProperty.flag: false });
não funciona Como isso pode ser feito corretamente?
javascript
reactjs
ecmascript-6
setstate
Alex Yong
fonte
fonte
Respostas:
Para
setState
um objeto aninhado, você pode seguir a abordagem abaixo, pois acho que setState não lida com atualizações aninhadas.A idéia é criar um objeto fictício, executar operações nele e, em seguida, substituir o estado do componente pelo objeto atualizado
Agora, o operador de propagação cria apenas uma cópia aninhada em nível do objeto. Se o seu estado estiver altamente aninhado, como:
Você pode definirState usando o operador spread em cada nível, como
No entanto, a sintaxe acima fica feia à medida que o estado se torna cada vez mais aninhado e, portanto, recomendo que você use o
immutability-helper
pacote para atualizar o estado.Veja esta resposta sobre como atualizar o estado com
immutability helper
.fonte
someProperty
e estamos modificando quethis.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}})
Um pouco tedioso ......prevState,
no último exemplo, você sósomeProperty
e seus filhosPara escrever em uma linha
fonte
this.state
imediatamente depoissetState
e espere que ele tenha um novo valor. Contra a chamadathis.state
internasetState
. Ou há também um problema com este último que não está claro para mim?this.state
depoissetState
. Além disso, não estamos passandothis.state
parasetState
. O…
operador espalha propriedades. É o mesmo que Object.assign (). github.com/tc39/proposal-object-rest-spreadthis.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });
poderia permitir evitar esse problema?Às vezes, as respostas diretas não são as melhores :)
Versão curta:
esse código
deve ser simplificado como algo como
Versão longa:
Atualmente, você não deve querer trabalhar com o estado aninhado no React . Como o React não está orientado para trabalhar com estados aninhados e todas as soluções propostas aqui parecem hacks. Eles não usam a estrutura, mas lutam com ela. Eles sugerem escrever um código não tão claro para fins duvidosos de agrupar algumas propriedades. Portanto, são muito interessantes como resposta ao desafio, mas praticamente inúteis.
Vamos imaginar o seguinte estado:
O que acontecerá se você alterar apenas um valor de
child1
? O React não renderiza novamente a exibição porque usa comparação superficial e descobre que aparent
propriedade não foi alterada. Aliás, a mutação direta do objeto de estado é considerada uma prática ruim em geral.Então você precisa recriar todo o
parent
objeto. Mas neste caso, encontraremos outro problema. O React pensará que todas as crianças mudaram seus valores e representará novamente todos eles. Claro que não é bom para o desempenho.Ainda é possível resolver esse problema escrevendo alguma lógica complicada,
shouldComponentUpdate()
mas eu preferiria parar por aqui e usar a solução simples da versão curta.fonte
aviso Legal
a resposta para sua miséria - veja o exemplo aqui
Há outra maneira mais curta de atualizar qualquer propriedade aninhada.
Em uma linha
Nota: Este aqui é o operador Vírgula ~ MDN ; veja em ação aqui (Sandbox) .
É semelhante a (embora isso não mude a referência de estado)
Para a diferença sutil neste contexto entre
forceUpdate
esetState
veja o exemplo vinculado.É claro que isso está abusando de alguns princípios básicos, como o
state
deve ser somente leitura, mas, como você está descartando imediatamente o estado antigo e o substituindo por um novo estado, está tudo bem.Atenção
Mesmo que o componente que contém o estado seja atualizado e renderizado corretamente ( exceto essa opção ) , os objetos não serão propagados para os filhos (veja o comentário do Spymaster abaixo) . Use essa técnica apenas se você souber o que está fazendo.
Por exemplo, você pode aprovar uma proposta simples alterada que é atualizada e aprovada com facilidade.
Agora, mesmo que a referência para complexNestedProp não tenha sido alterada ( shouldComponentUpdate )
o componente será renderizado novamente sempre que o componente pai for atualizado, que é o caso após a chamada
this.setState
outhis.forceUpdate
no pai.Efeitos da mutação do estado
O uso de estado aninhado e a mutação direta do estado são perigosos porque objetos diferentes podem conter (intencionalmente ou não) referências diferentes (mais antigas) ao estado e podem não necessariamente saber quando atualizar (por exemplo, ao usar
PureComponent
ou seshouldComponentUpdate
é implementado para retornarfalse
) OU são destinado a exibir dados antigos, como no exemplo abaixo.De qualquer forma, aqui você pode ver que
Nested PureChildClass
ele não foi renderizado novamente porque os objetos não foram propagados.fonte
state
completamente e usa propriedades observáveis personalizadas . O React'ssetState
é apenas uma conveniência embutida, mas você logo percebe que ela tem seus limites. O uso de propriedades personalizadas e o uso inteligente deforceUpdate
oferecem muito mais. Use Observables em vez de state nos componentes React.this.forceUpdate()
ou implementar específicoshouldComponentUpdate
.Se você estiver usando o ES2015, terá acesso ao Object.assign. Você pode usá-lo da seguinte maneira para atualizar um objeto aninhado.
Você mescla as propriedades atualizadas com as existentes e usa o objeto retornado para atualizar o estado.
Editar: Adicionado um objeto vazio como destino à função de atribuição para garantir que o estado não seja alterado diretamente, como apontado pelo carkod.
fonte
fonte
property
contiver várias propriedades aninhadas, o primeiro as excluirá e o segundo não. codesandbox.io/s/nameless-pine-42thuExistem muitas bibliotecas para ajudar com isso. Por exemplo, usando o immutability-helper :
Usando lodash / fp set:
Usando lodash / fp merge:
fonte
lodash
, provavelmente desejará tentar_.cloneDeep
definir o estado como a cópia clonada.lodash/fp
, para que não tenhamos que nos preocupar com mutações.merge
ouset
funcionar no lodash / fp além da sintaxe?this.setState(newState)
os métodos lodash / fp. Outro problema é que o lodash.set
(sem FP ) tem uma ordem diferente de argumentos que me atrapalharam por um tempo.Usamos o Immer https://github.com/mweststrate/immer para lidar com esses tipos de problemas.
Acabei de substituir esse código em um de nossos componentes
Com isso
Com o immer, você lida com o seu estado como um "objeto normal". A mágica acontece nos bastidores com objetos proxy.
fonte
Aqui está uma variação da primeira resposta dada neste tópico, que não requer pacotes extras, bibliotecas ou funções especiais.
Para definir o estado de um campo aninhado específico, você definiu o objeto inteiro. Fiz isso criando uma variável
newState
e espalhando o conteúdo do estado atual primeiro usando o operador de dispersão ES2015 . Em seguida, substituí o valor dethis.state.flag
com o novo valor (desde que eu definiflag: value
depois que eu espalhei o estado atual no objeto, oflag
campo no estado atual é substituído). Então, simplesmente defino o estado desomeProperty
para o meunewState
objeto.fonte
Embora o aninhamento não seja realmente como você deve tratar um estado de componente, às vezes é algo fácil para o aninhamento de camada única.
Para um estado como este
Um método reutilizável usado seria assim.
basta passar o nome do objeto para cada aninhamento que você deseja endereçar ...
fonte
Eu usei essa solução.
Se você tiver um estado aninhado como este:
você pode declarar a função handleChange que copia o status atual e o atribui novamente com valores alterados
aqui o html com o ouvinte de evento
fonte
Crie uma cópia do estado:
faça alterações neste objeto:
agora atualize o estado
fonte
Embora você tenha perguntado sobre um estado do componente React baseado em classe, o mesmo problema existe com o gancho useState. Pior ainda: o gancho useState não aceita atualizações parciais. Portanto, essa pergunta se tornou muito relevante quando o gancho useState foi introduzido.
Decidi postar a seguinte resposta para garantir que a pergunta cubra cenários mais modernos nos quais o gancho useState é usado:
Se você tem:
você pode definir a propriedade aninhada clonando a corrente e corrigindo os segmentos necessários dos dados, por exemplo:
Ou você pode usar a biblioteca Immer para simplificar a clonagem e aplicação de patches do objeto.
Ou você pode usar a biblioteca Hookstate (exoneração de responsabilidade: eu sou um autor) para simplesmente gerenciar completamente os dados estatais complexos (locais e globais) e melhorar o desempenho (leia-se: para não se preocupar com a otimização da renderização):
obtenha o campo para renderizar:
defina o campo aninhado:
Aqui está o exemplo de Hookstate, onde o estado é aninhado profundamente / recursivamente na estrutura de dados do tipo árvore .
fonte
Duas outras opções ainda não mencionadas:
fonte
Para tornar as coisas genéricas, trabalhei nas respostas de @ ShubhamKhatri e @ Qwerty.
objeto de estado
controles de entrada
método updateState
setState como resposta de @ ShubhamKhatri
setState como a resposta de @ Qwerty
Nota: Esses métodos acima não funcionam para matrizes
fonte
Levo muito a sério as preocupações já expressas em torno da criação de uma cópia completa do seu estado componente. Com isso dito, eu sugeriria fortemente Immer .
Isso deve funcionar
React.PureComponent
(por exemplo, comparações de estado superficial com o React), poisImmer
habilmente usa um objeto proxy para copiar eficientemente uma árvore de estado arbitrariamente profunda. O Immer também é mais tipicamente seguro em comparação com bibliotecas como o Immutability Helper e é ideal para usuários de Javascript e Typescript.Função de utilitário de texto datilografado
fonte
fonte
obj
é apenas uma referência para o estado, então por isso que você está transformando o realthis.state
objetoDescobri que isso funcionava para mim, tendo um formulário de projeto no meu caso em que, por exemplo, você tem um ID e um nome, e prefiro manter o estado de um projeto aninhado.
Avise-se me!
fonte
Algo assim pode ser suficiente,
fonte
Eu sei que é uma pergunta antiga, mas ainda queria compartilhar como consegui isso. Assumindo que o estado no construtor se parece com isso:
Minha
handleChange
função é assim:E certifique-se de nomear as entradas de acordo:
fonte
Faço atualizações aninhadas com uma pesquisa reduzida :
Exemplo:
As variáveis aninhadas no estado:
A função:
Usar:
fonte
Este é o meu estado inicial
O gancho ou você pode substituí-lo pelo estado (componente de classe)
O método para handleChange
Método para definir estado com estados aninhados
Finalmente, esta é a entrada que eu uso
fonte
Se você estiver usando o formik em seu projeto, ele tem uma maneira fácil de lidar com essas coisas. Aqui está a maneira mais fácil de fazer com o formik.
Primeiro defina seus valores iniciais dentro do atributo formik initivalues ou no react. Estado
Aqui, os valores iniciais são definidos no estado de reação
define acima valores iniciais para o campo formik dentro do
initiValues
atributo formikFaça um console para verificar o estado atualizado em
string
vez da funçãoboolean
formiksetFieldValue
para definir o estado ou vá com a ferramenta debugger react para ver as alterações nos valores do estado do formik.fonte
tente este código:
fonte
someProperty
e após a execução do código acima, somente aflag
propriedade permaneceráeu vi o seguinte em um livro:
mas não tenho certeza se está certo ..
fonte