Eu tenho dois componentes
- Componente pai
- Componente filho
Eu estava tentando chamar o método da criança de Parent, tentei dessa maneira, mas não consegui um resultado
class Parent extends Component {
render() {
return (
<Child>
<button onClick={Child.getAlert()}>Click</button>
</Child>
);
}
}
class Child extends Component {
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
Existe uma maneira de chamar o método da criança dos pais?
Nota: Os componentes filho e pai estão em dois arquivos diferentes
javascript
reactjs
N8FURY
fonte
fonte
Respostas:
Primeiro, deixe-me expressar que esse geralmente não é o caminho a seguir nas coisas no React Land. Geralmente, o que você deseja fazer é passar a funcionalidade para crianças em objetos e passar notificações de crianças em eventos (ou melhor ainda
dispatch
:).Mas se você deve expor um método imperativo em um componente filho, pode usar refs . Lembre-se de que é uma escotilha de escape e geralmente indica que um design melhor está disponível.
Usando ganchos e componentes de função (
>= [email protected]
)A documentação para
useImperativeHandle()
está aqui :Usando componentes de classe (
>= [email protected]
)API herdada (
<= [email protected]
)Para fins históricos, eis o estilo baseado em retorno de chamada que você usaria nas versões React anteriores a 16.3:
fonte
connect
retorna um componente de ordem superior que envolve sua instância original. Você precisará chamargetWrappedInstance()
o componente conectado primeiro para obter o componente original. Então você pode chamar métodos de instância nisso.componentWillReceiveProps
e o usará como gatilho.Você pode usar outro padrão aqui:
O que ele faz é definir o
clickChild
método dos pais quando o filho é montado. Dessa forma, quando você clica no botão em pai, ele chamará oclickChild
que chama de filhogetAlert
.Isso também funciona se o seu filho estiver envolvido,
connect()
para que você não precise dogetWrappedInstance()
hack.Observe que você não pode usar
onClick={this.clickChild}
no pai porque, quando o pai é renderizado, o filho não está montado ethis.clickChild
ainda não está designado. UsaronClick={() => this.clickChild()}
é bom porque quando você clica no botãothis.clickChild
já deve estar atribuído.fonte
_this2.clickChild is not a function
porque?https://facebook.github.io/react/tips/expose-component-functions.html para obter mais respostas, ref ref aqui Métodos de chamada sobre componentes React child
Ao examinar as referências do componente "reason", você está quebrando o encapsulamento e tornando impossível refatorar esse componente sem examinar cuidadosamente todos os lugares em que é usado. Por esse motivo, é altamente recomendável tratar os árbitros como privados para um componente, bem como o estado.
Em geral, os dados devem ser transmitidos pela árvore por meio de adereços. Existem algumas exceções a isso (como chamar .focus () ou acionar uma animação única que realmente não "altera" o estado), mas sempre que você está expondo um método chamado "conjunto", os adereços geralmente são uma escolha melhor. Tente fazer com que o componente de entrada interno se preocupe com seu tamanho e aparência, para que nenhum de seus ancestrais o faça.
fonte
Método alternativo com useEffect:
Pai:
Crianças:
fonte
Podemos usar refs de outra maneira, como
Nós vamos criar um elemento Parent, ele renderizará um
<Child/>
componente. Como você pode ver, o componente que será renderizado, você precisa adicionar o atributo ref e fornecer um nome para ele.Então, a
triggerChildAlert
função, localizada na classe pai, acessará a propriedade refs desse contexto (quando atriggerChildAlert
função for acionada, acessará a referência filho e terá todas as funções do elemento filho).Agora, o componente filho, como teoricamente projetado anteriormente, terá a seguinte aparência:
Aqui está o código fonte - a
Hope irá ajudá-lo!
fonte
Se você estiver fazendo isso simplesmente porque deseja que a Criança forneça uma característica reutilizável para seus pais, considere fazer isso usando acessórios de renderização .
Essa técnica realmente vira a estrutura de cabeça para baixo. O
Child
agora envolve o pai, então eu o renomei paraAlertTrait
abaixo. Eu mantive o nomeParent
de continuidade, embora não seja realmente um pai agora.Nesse caso, o AlertTrait fornece uma ou mais características que ele transmite como adereços para qualquer componente que foi fornecido em seu
renderComponent
suporte.O pai recebe
doAlert
como suporte e pode chamá-lo quando necessário.(Para maior clareza, chamei o suporte
renderComponent
no exemplo acima. Mas nos documentos do React vinculados acima, eles chamam derender
.)O componente Trait pode renderizar coisas ao redor do pai, em sua função de renderização, mas não renderiza nada dentro do pai. Na verdade, ele poderia renderizar coisas dentro dos Pais, se passasse por outro objeto (por exemplo,
renderChild
) para o pai, que ele poderia usar durante seu método de renderização.Isso é um pouco diferente do que o OP solicitou, mas algumas pessoas podem acabar aqui (como nós) porque queriam criar uma característica reutilizável e pensavam que um componente filho era uma boa maneira de fazer isso.
fonte
this.clickChild = click
, mas seus vários cronômetros passariam múltiplas funções, assim que você precisa para armazenar todos eles:this.watchRestartFuncs[watchId] = restartWatch
Você pode conseguir isso facilmente dessa maneira
Passos-
No componente filho, acesse essa variável usando props e execute o método desejado, tendo uma condição if.
fonte
Estou usando o
useEffect
hook para superar a dor de cabeça de fazer tudo isso, agora passo uma variável para uma criança assim:fonte
Não fiquei satisfeito com nenhuma das soluções apresentadas aqui. Na verdade, existe uma solução muito simples que pode ser feita usando Javascript puro, sem depender de alguma funcionalidade do React que não seja o objeto props básico - e oferece o benefício de se comunicar em qualquer direção (pai -> filho, filho -> pai). Você precisa passar um objeto do componente pai para o componente filho. Esse objeto é o que eu chamo de "referência bidirecional" ou biRef, para abreviar. Basicamente, o objeto contém uma referência aos métodos no pai que ele deseja expor. E o componente filho anexa métodos ao objeto que o pai pode chamar. Algo assim:
A outra vantagem dessa solução é que você pode adicionar muito mais funções no pai e no filho enquanto as passa do pai para o filho usando apenas uma única propriedade.
Uma melhoria em relação ao código acima é não adicionar as funções pai e filho diretamente ao objeto biRef, mas aos sub-membros. As funções pai devem ser adicionadas a um membro chamado "pai", enquanto as funções filho devem ser adicionadas a um membro chamado "filho".
Ao colocar as funções pai e filho em membros separados do objeto biRef, você terá uma separação limpa entre os dois e verá facilmente quais pertencem ao pai ou ao filho. Também ajuda a impedir que um componente filho substitua acidentalmente uma função pai, se a mesma função aparecer em ambos.
Uma última coisa é que, se você observar, o componente pai cria o objeto biRef com var, enquanto o componente filho acessa-o através do objeto props. Pode ser tentador não definir o objeto biRef no pai e acessá-lo de seu pai por meio de seu próprio parâmetro props (que pode ser o caso em uma hierarquia de elementos da interface do usuário). Isso é arriscado, porque a criança pode pensar que uma função que está chamando no pai pertence ao pai quando ele realmente pertence a um avô. Não há nada errado com isso, desde que você esteja ciente disso. A menos que você tenha um motivo para apoiar alguma hierarquia além de um relacionamento pai / filho, é melhor criar o biRef no seu componente pai.
fonte
Você pode fazer a Inversão de Herança (consulte aqui: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e ). Dessa forma, você tem acesso à instância do componente que você estaria quebrando (assim, você poderá acessar suas funções)
fonte
Eu acho que a maneira mais básica de chamar métodos é definindo uma solicitação no componente filho. Assim que o filho manipula a solicitação, ele chama um método de retorno de chamada para redefinir a solicitação.
O mecanismo de redefinição é necessário para poder enviar a mesma solicitação várias vezes uma após a outra.
No componente pai
No método de renderização do pai:
O pai precisa de 2 métodos, para se comunicar com seu filho em 2 direções.
No componente filho
O filho atualiza seu estado interno, copiando a solicitação dos acessórios.
Finalmente, ele lida com a solicitação e envia a redefinição ao pai:
fonte
Outra maneira de acionar uma função filho do pai é fazer uso da
componentDidUpdate
função no Componente filho. Eu passo uma propostatriggerChildFunc
de pai para filho, que inicialmente énull
. O valor muda para uma função quando o botão é clicado e o Child percebe a alteraçãocomponentDidUpdate
e chama sua própria função interna.Como o prop
triggerChildFunc
muda para uma função, também recebemos um retorno de chamada para o pai. Se o pai não precisar saber quando a função é chamada, o valortriggerChildFunc
poderá, por exemplo, mudar denull
paratrue
.CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010
fonte
Aqui está minha demonstração: https://stackblitz.com/edit/react-dgz1ee?file=styles.css
Estou usando
useEffect
para chamar os métodos do componente filho. Eu tentei com,Proxy and Setter_Getter
mas agorauseEffect
parece ser a maneira mais conveniente de chamar um método filho do pai. Para usá-Proxy and Setter_Getter
lo, parece que há alguma sutileza a ser superada primeiro, porque o elemento renderizado primeiro é o elemento de um objectLike através daref.current return => <div/>
especificidade do. Com relação a issouseEffect
, você também pode aproveitar essa abordagem para definir o estado dos pais, dependendo do que você deseja fazer com os filhos.No link da demonstração que forneci, você encontrará o código completo do ReactJS com meus rascunhos dentro para que você possa apreciar o fluxo de trabalho da minha solução.
Aqui estou fornecendo a você o snippet do meu ReactJS apenas com o código relevante. :
fonte
Estamos felizes com um gancho personalizado que chamamos
useCounterKey
. Ele apenas configura uma counterKey, ou uma chave que conta a partir de zero. A função que ele retorna redefine a tecla (ou seja, incremento). (Acredito que essa é a maneira mais idiomática do React para redefinir um componente - basta pressionar a tecla).No entanto, esse gancho também funciona em qualquer situação em que você deseja enviar uma mensagem única ao cliente para fazer alguma coisa. Por exemplo, nós o usamos para focar um controle no filho em um determinado evento pai - ele apenas se concentra automaticamente sempre que a chave é atualizada. (Se mais adereços forem necessários, eles poderão ser configurados antes de redefinir a chave para que fiquem disponíveis quando o evento acontecer.)
Esse método tem uma curva de aprendizado b / c, não é tão simples quanto um manipulador de eventos típico, mas parece a maneira mais idiomática de lidar com isso no React que encontramos (já que as teclas já funcionam dessa maneira). Def aberto a feedback sobre esse método, mas está funcionando bem!
Exemplos de usos:
(Crédito a Kent Dodds pelo conceito counterKey .)
fonte
Aqui está um bug? a procurar: Concordo com a solução da rossipedia usando forwardRef, useRef, useImperativeHandle
Há algumas informações erradas online que afirmam que refs só podem ser criadas a partir de componentes da classe React, mas você pode realmente usar componentes de função se usar os ganchos acima mencionados. Uma observação: os ganchos só funcionaram para mim depois que eu mudei o arquivo para não usar withRouter () ao exportar o componente. Ou seja, uma mudança de
em vez disso ser
Em retrospectiva, o withRouter () não é necessário para esse componente, mas geralmente não prejudica nada que esteja nele. Meu caso de uso é que eu criei um componente para criar uma Tabela para lidar com a visualização e edição dos valores de configuração, e eu queria poder dizer a esse componente filho para redefinir seus valores de estado sempre que o botão Redefinir do formulário pai fosse pressionado. UseRef () não obteria adequadamente o ref ou ref.current (continuando sendo nulo) até que eu removesse withRouter () do arquivo que contém meu componente filho TableConfig
fonte