- Suponha que eu possua uma classe React P, que renderize duas classes filho, C1 e C2.
- C1 contém um campo de entrada. Vou me referir a este campo de entrada como Foo.
- Meu objetivo é deixar o C2 reagir às mudanças no Foo.
Eu vim com duas soluções, mas nenhuma delas parece estar certa.
Primeira solução:
- Atribua P um estado
state.input
,. - Crie uma
onChange
função em P, que recebe um evento e definestate.input
. - Passe isso
onChange
para C1 como aprops
e deixe C1 ligarthis.props.onChange
- se aoonChange
de Foo.
Isso funciona. Sempre que o valor de Foo muda, ele dispara a setState
em P, então P terá a entrada para passar para C2.
Mas não parece certo pelo mesmo motivo: estou definindo o estado de um elemento pai a partir de um elemento filho. Isso parece trair o princípio de design do React: fluxo de dados de direção única.
É assim que eu devo fazê-lo ou há uma solução mais natural para reagir?
Segunda solução:
Basta colocar Foo em P.
Mas esse é um princípio de design que devo seguir quando estruturar meu aplicativo - colocando todos os elementos de formulário na render
classe de nível mais alto?
Como no meu exemplo, se eu tiver uma renderização grande de C1, não quero colocar todo o render
C1 em render
P apenas porque C1 tem um elemento de formulário.
Como devo fazer isso?
Respostas:
Então, se estou entendendo corretamente, sua primeira solução está sugerindo que você esteja mantendo o estado em seu componente raiz? Não posso falar pelos criadores do React, mas geralmente acho que essa é uma solução adequada.
Manter o estado é uma das razões (pelo menos eu acho) que o React foi criado. Se você já implementou seu próprio lado do cliente de padrão de estado para lidar com uma interface de usuário dinâmica que possui muitas peças móveis interdependentes, você vai adorar o React, porque alivia muito dessa dor de gerenciamento de estado.
Mantendo o estado ainda mais na hierarquia e atualizando-o através de eventos, seu fluxo de dados ainda é praticamente unidirecional; você está apenas respondendo a eventos no componente Raiz; na verdade, não está obtendo os dados por meio de ligação bidirecional, você está dizendo ao componente Raiz que "ei, algo aconteceu aqui, verifique os valores" ou está passando o estado de alguns dados no componente filho para atualizar o estado. Você alterou o estado em C1 e deseja que o C2 esteja ciente disso, portanto, atualizando o estado no componente Raiz e renderizando novamente, os objetos de suporte do C2 agora estão sincronizados desde que o estado foi atualizado no componente Raiz e transmitido adiante .
fonte
C2
tiver umgetInitialState
para dados e dentro do querender
ele usathis.state.data
?Depois de usar o React para criar um aplicativo agora, gostaria de compartilhar algumas reflexões sobre esta pergunta que fiz há meio ano.
Eu recomendo que você leia
A primeira postagem é extremamente útil para entender como você deve estruturar seu aplicativo React.
O Flux responde à pergunta por que você deve estruturar seu aplicativo React dessa maneira (em vez de como estruturá-lo). A reação é de apenas 50% do sistema, e com o Flux você pode ver toda a imagem e ver como eles constituem um sistema coerente.
Voltar para a pergunta.
Quanto à minha primeira solução, não há problema em deixar o manipulador ir na direção inversa, pois os dados ainda estão indo na direção única.
No entanto, se deixar um manipulador acionar um setState em P pode estar certo ou errado, dependendo da sua situação.
Se o aplicativo for um simples conversor Markdown, sendo C1 a entrada bruta e C2 a saída HTML, não há problema em deixar C1 acionar um setState em P, mas alguns podem argumentar que essa não é a maneira recomendada de fazer isso.
No entanto, se o aplicativo for uma lista de tarefas, C1 sendo a entrada para a criação de uma nova tarefa, C2 a lista de tarefas em HTML, você provavelmente desejará que o manipulador suba dois níveis acima de P - para o
dispatcher
que permite astore
atualizaçãodata store
, que envia os dados para P e preenche as visualizações. Veja o artigo do Flux. Aqui está um exemplo: Flux - TodoMVCGeralmente, prefiro a maneira descrita no exemplo da lista de tarefas. Quanto menos estado você tiver no seu aplicativo, melhor.
fonte
Cinco anos depois, com a introdução dos React Hooks, agora existe uma maneira muito mais elegante de fazê-lo com o uso do useContext hook.
Você define o contexto em um escopo global, exporta variáveis, objetos e funções no componente pai e, em seguida, agrupa os filhos no aplicativo em um contexto fornecido e importa o que for necessário nos componentes filhos. Abaixo está uma prova de conceito.
Você pode executar este exemplo no editor de Code Sandbox.
fonte
A primeira solução, mantendo o estado no componente pai , é a correta . No entanto, para problemas mais complexos, você deve pensar em alguma biblioteca de gerenciamento de estado , redux é o mais popular usado com o react.
fonte
Estou surpreso que não haja respostas com uma solução React idiomática direta no momento em que estou escrevendo. Então, aqui está (compare o tamanho e a complexidade com os outros):
Qualquer controle
input
(maneira idiomática de trabalhar com formulários no React) atualiza o estado pai em seuonChange
retorno de chamada e ainda não trai nada.Observe atentamente o componente C1, por exemplo. Você vê alguma diferença significativa na forma como
C1
e built-ininput
alça componente as mudanças de estado? Você não deveria, porque não há. A elevação do estado e a transmissão de pares value / onChange são idiomáticas para o React bruto. Não uso de referências, como sugerem algumas respostas.fonte
this.state
, o retorno estava ausente na renderização e vários componentes devem ser agrupados em div ou algo assim. Não sei como eu perdi isso quando escrevi a resposta original. Deve ter sido o erro de edição.Resposta mais recente com um exemplo, que usa
React.useState
Manter o estado no componente pai é a maneira recomendada. O pai precisa ter acesso a ele, pois o gerencia em dois componentes filhos. Mover para o estado global, como o gerenciado pelo Redux, não é recomendado pelo mesmo motivo pelo qual a variável global é pior do que a local em geral na engenharia de software.
Quando o estado está no componente pai, o filho pode modificá-lo se o pai fornecer o filho
value
e oonChange
manipulador em adereços (às vezes é chamado de link de valor ou padrão de link de estado ). Aqui está como você faria isso com ganchos:Todo o componente pai será renderizado novamente na alteração de entrada no filho, o que pode não ser um problema se o componente pai for pequeno / rápido para ser renderizado novamente. O desempenho de re-renderização do componente pai ainda pode ser um problema no caso geral (por exemplo, formulários grandes). Este é o problema resolvido no seu caso (veja abaixo).
O padrão de link de estado e nenhuma re-renderização pai são mais fáceis de implementar usando a biblioteca de terceiros, como Hookstate - sobrecarregada
React.useState
para cobrir diversos casos de uso, incluindo o seu. (Aviso: sou autor do projeto).Aqui está como ficaria com o Hookstate.
Child1
mudará a entrada,Child2
reagirá a ela.Parent
manterá o estado, mas não será renderizado novamente, somenteChild1
eChild2
continuará.PS: existem muitos outros exemplos aqui, cobrindo cenários semelhantes e mais complicados, incluindo dados profundamente aninhados, validação de estado, estado global com
setState
gancho, etc. Há também um aplicativo de amostra completo online , que usa o Hookstate e a técnica explicada acima.fonte
Você deve aprender as bibliotecas Redux e ReactRedux. Ele estruturará seus estados e objetos em uma loja e você poderá acessá-los posteriormente em seus componentes.
fonte
Com React> = 16.3, você pode usar ref e forwardRef, para obter acesso ao DOM da criança a partir do pai. Não use mais o modo antigo de referências.
Aqui está o exemplo usando o seu caso:
Consulte Refs e ForwardRef para obter informações detalhadas sobre refs e forwardRef.
fonte
shouldComponentUpdate(nextProps, nextState)
O código abaixo usa
@bound
anotações do ES.Nextbabel-plugin-transform-decorators-legacy
do BabelJS 6 e propriedades de classe (a anotação define esse valor nas funções de membros semelhantes à ligação):fonte
O conceito de passar dados de pai para filho e vice-versa é explicado.
fonte