Tengo dos componentes
- Componente principal
- Componente hijo
Estaba tratando de llamar al método del niño desde Parent, lo intenté de esta manera pero no pude obtener un 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>
);
}
}
¿Hay alguna forma de llamar al método del niño desde el padre?
Nota: Los componentes secundarios y principales están en dos archivos diferentes.
javascript
reactjs
N8FURY
fuente
fuente
Respuestas:
En primer lugar, permítanme expresar que, en general, esta no es la forma de hacer las cosas en React land. Por lo general, lo que desea hacer es transmitir la funcionalidad a los niños en accesorios y pasar notificaciones de los niños en eventos (o mejor aún:)
dispatch
.Pero si debe exponer un método imperativo en un componente secundario, puede usar referencias . Recuerde que esta es una escotilla de escape y generalmente indica que hay un mejor diseño disponible.
Uso de ganchos y componentes de función (
>= [email protected]
)La documentación para
useImperativeHandle()
está aquí :Usar componentes de clase (
>= [email protected]
)API heredada (
<= [email protected]
)Para fines históricos, este es el estilo basado en la devolución de llamada que usaría con las versiones React anteriores a 16.3:
fuente
connect
devuelve un componente de orden superior que envuelve su instancia original. Deberá llamargetWrappedInstance()
primero al componente conectado para obtener su componente original. Entonces puede llamar a métodos de instancia sobre eso.componentWillReceiveProps
y lo usará como disparador.Puedes usar otro patrón aquí:
Lo que hace es establecer el
clickChild
método del padre cuando se monta el hijo. De esta manera, cuando hace clic en el botón en padre, llamará aclickChild
qué llamadasgetAlert
.Esto también funciona si su hijo está envuelto
connect()
para que no necesitegetWrappedInstance()
hack.Tenga en cuenta que no puede usar
onClick={this.clickChild}
en padre porque cuando el padre se representa, el hijo no está montado, porthis.clickChild
lo que aún no está asignado. UsaronClick={() => this.clickChild()}
está bien porque cuando haces clic en el botónthis.clickChild
ya debería estar asignado.fuente
_this2.clickChild is not a function
por qué?https://facebook.github.io/react/tips/expose-component-functions.html para obtener más respuestas, consulte aquí Métodos de llamada en componentes React child
Al examinar las referencias del componente "razón", está rompiendo la encapsulación y haciendo imposible refactorizar ese componente sin examinar cuidadosamente todos los lugares donde se utiliza. Debido a esto, recomendamos encarecidamente tratar las referencias como privadas para un componente, al igual que el estado.
En general, los datos deben pasarse por el árbol a través de accesorios. Hay algunas excepciones a esto (como llamar a .focus () o activar una animación única que realmente no "cambia" el estado), pero cada vez que expones un método llamado "set", los accesorios generalmente son Una mejor opción. Intente que el componente de entrada interno se preocupe por su tamaño y apariencia para que ninguno de sus antepasados lo haga.
fuente
Método alternativo con useEffect:
Padre:
Niños:
fuente
Podemos usar referencias de otra manera como-
Vamos a crear un elemento primario, que representará un
<Child/>
componente. Como puede ver, el componente que se representará, debe agregar el atributo ref y proporcionarle un nombre.Luego, la
triggerChildAlert
función, ubicada en la clase padre, accederá a la propiedad refs de este contexto (cuandotriggerChildAlert
se activa la función accederá a la referencia secundaria y tendrá todas las funciones del elemento secundario).Ahora, el componente hijo, como se diseñó teóricamente anteriormente, se verá así:
Aquí está el código fuente: ¡
Hope te ayudará!
fuente
Si está haciendo esto simplemente porque quiere que el Niño proporcione un rasgo reutilizable a sus padres, entonces puede considerar hacerlo usando accesorios de renderizado .
Esa técnica realmente pone la estructura al revés. El
Child
ahora envuelve al padre, por lo que lo he renombrado aAlertTrait
continuación. Mantuve el nombreParent
de continuidad, aunque en realidad no es un padre ahora.En este caso, AlertTrait proporciona uno o más rasgos que pasa como accesorios a cualquier componente que se le haya dado en su
renderComponent
accesorio.El padre recibe
doAlert
como accesorio y puede llamarlo cuando sea necesario.(Para mayor claridad, llamé al accesorio
renderComponent
en el ejemplo anterior. Pero en los documentos React vinculados anteriormente, simplemente lo llamanrender
).El componente Trait puede representar cosas que rodean al elemento primario, en su función de representación, pero no representa nada dentro del elemento primario. En realidad, podría representar cosas dentro del padre, si pasara otro accesorio (por ejemplo,
renderChild
) al padre, que el padre podría usar durante su método de renderizado.Esto es algo diferente de lo que solicitó el OP, pero algunas personas podrían terminar aquí (como lo hicimos nosotros) porque querían crear un rasgo reutilizable, y pensaron que un componente hijo era una buena manera de hacerlo.
fuente
this.clickChild = click
pero sus múltiples cronómetros pasarían múltiples funciones, por lo que necesitaría almacenarlos todos:this.watchRestartFuncs[watchId] = restartWatch
Puede lograr esto fácilmente de esta manera
Pasos-
Desde el componente secundario, acceda a esa variable utilizando accesorios y ejecute el método que desee teniendo una condición if.
fuente
Estoy usando
useEffect
hook para superar el dolor de cabeza de hacer todo esto, así que ahora paso una variable a un niño como este:fuente
No estaba satisfecho con ninguna de las soluciones presentadas aquí. En realidad, hay una solución muy simple que se puede hacer usando Javascript puro sin depender de alguna funcionalidad React que no sea el objeto de accesorios básicos, y le brinda el beneficio de comunicarse en cualquier dirección (padre -> niño, niño -> padre). Debe pasar un objeto del componente primario al componente secundario. Este objeto es a lo que me refiero como una "referencia bidireccional" o biRef para abreviar. Básicamente, el objeto contiene una referencia a métodos en el padre que el padre quiere exponer. Y el componente hijo adjunta métodos al objeto que el padre puede llamar. Algo como esto:
La otra ventaja de esta solución es que puede agregar muchas más funciones en el padre y el hijo mientras las pasa del padre al hijo usando solo una propiedad.
Una mejora sobre el código anterior es no agregar las funciones padre e hijo directamente al objeto biRef, sino más bien a los miembros secundarios. Las funciones primarias deben agregarse a un miembro llamado "primario", mientras que las funciones secundarias deben agregarse a un miembro llamado "secundario".
Al colocar las funciones padre e hijo en miembros separados del objeto biRef, tendrá una separación clara entre los dos y verá fácilmente cuáles pertenecen al padre o hijo. También ayuda a evitar que un componente secundario sobrescriba accidentalmente una función principal si la misma función aparece en ambas.
Una última cosa es que si observa que el componente primario crea el objeto biRef con var, mientras que el componente secundario accede a él a través del objeto props. Puede ser tentador no definir el objeto biRef en el padre y acceder a él desde su padre a través de su propio parámetro de accesorios (que podría ser el caso en una jerarquía de elementos de la interfaz de usuario). Esto es arriesgado porque el niño puede pensar que una función que está llamando al padre pertenece al padre cuando en realidad podría pertenecer a un abuelo. No hay nada de malo en esto, siempre y cuando lo sepas. A menos que tenga una razón para apoyar alguna jerarquía más allá de una relación padre / hijo, es mejor crear biRef en su componente padre.
fuente
Puede realizar la Inversión de herencia (búsquela aquí: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e ). De esa manera, tiene acceso a la instancia del componente que estaría envolviendo (por lo tanto, podrá acceder a sus funciones)
fuente
Creo que la forma más básica de llamar a los métodos es estableciendo una solicitud en el componente secundario. Luego, tan pronto como el niño maneja la solicitud, llama a un método de devolución de llamada para restablecer la solicitud.
El mecanismo de reinicio es necesario para poder enviar la misma solicitud varias veces una tras otra.
En componente principal
En el método de representación del padre:
El padre necesita 2 métodos, para comunicarse con su hijo en 2 direcciones.
En componente hijo
El niño actualiza su estado interno, copiando la solicitud de los accesorios.
Luego, finalmente maneja la solicitud y envía el restablecimiento al padre:
fuente
Otra forma de activar una función secundaria desde el elemento primario es hacer uso de la
componentDidUpdate
función en Componente secundario. Le paso un accesoriotriggerChildFunc
de padre a hijo, que inicialmente esnull
. El valor cambia a una función cuando se hace clic en el botón y Child nota que ese cambiocomponentDidUpdate
y llama a su propia función interna.Como prop
triggerChildFunc
cambia a una función, también recibimos una devolución de llamada a Parent. Si Parent no necesita saber cuándo se llama a la función, el valortriggerChildFunc
podría, por ejemplo, cambiar denull
atrue
.CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010
fuente
Aquí mi demo: https://stackblitz.com/edit/react-dgz1ee?file=styles.css
Estoy usando
useEffect
para llamar a los métodos del componente hijos. Lo he intentado,Proxy and Setter_Getter
pero hasta ahorauseEffect
parece ser la forma más conveniente de llamar a un método hijo desde el padre. Para usarloProxy and Setter_Getter
, parece que hay algo de sutileza que superar primero, porque el elemento representado en primer lugar es un elemento similar a un objeto a través de laref.current return => <div/>
especificidad de. Con respecto a estouseEffect
, también puede aprovechar este enfoque para establecer el estado de los padres dependiendo de lo que quiera hacer con los hijos.En el enlace de la demostración que he proporcionado, encontrará el código completo de mi ReactJS con mi dibujo interno para que pueda apreciar el flujo de trabajo de mi solución.
Aquí le proporciono el fragmento de mi ReactJS solo con el código relevante. :
fuente
Estamos contentos con un gancho personalizado que llamamos
useCounterKey
. Simplemente configura una counterKey, o una clave que cuenta desde cero. La función que devuelve restablece la tecla (es decir, incremento). (Creo que esta es la forma más idiomática en React para restablecer un componente, solo golpee la tecla).Sin embargo, este enlace también funciona en cualquier situación en la que desee enviar un mensaje único al cliente para que haga algo. Por ejemplo, lo usamos para enfocar un control en el niño en un determinado evento padre; solo se enfoca automáticamente cada vez que se actualiza la clave. (Si se necesitan más accesorios, se pueden configurar antes de restablecer la clave para que estén disponibles cuando ocurra el evento).
Este método tiene un poco de una curva de aprendizaje b / c, no es tan sencillo como un controlador de eventos típico, pero parece la forma más idiomática de manejar esto en React que hemos encontrado (ya que las teclas ya funcionan de esta manera). Definitivamente abierto a comentarios sobre este método, pero está funcionando bien.
Usos de muestra:
(Crédito a Kent Dodds por el concepto counterKey ).
fuente
Aquí hay un error? a tener en cuenta: estoy de acuerdo con la solución de rossipedia usando forwardRef, useRef, useImperativeHandle
Hay cierta información errónea en línea que dice que las referencias solo se pueden crear a partir de los componentes React Class, pero de hecho puedes usar Function Components si usas los ganchos mencionados anteriormente. Una nota, los ganchos solo funcionaron para mí después de que cambié el archivo para no usar withRouter () al exportar el componente. Es decir, un cambio de
en lugar de ser
En retrospectiva, withRouter () no es necesario para dicho componente de todos modos, pero por lo general no hace daño tenerlo. Mi caso de uso es que creé un componente para crear una Tabla para manejar la visualización y edición de valores de configuración, y quería poder decirle a este componente secundario que restablezca sus valores de estado cada vez que se presiona el botón Restablecer del formulario principal. UseRef () no obtendría adecuadamente ref o ref.current (seguía siendo nulo) hasta que elimine withRouter () del archivo que contiene mi componente hijo TableConfig
fuente