
Wojciech Kulma
Mi estructura queda de la siguiente manera:
Component 1
- |- Component 2
- - |- Component 4
- - - |- Component 5
Component 3
El Componente 3 debería mostrar algunos datos según el estado del Componente 5.
Dado que los accesorios son inmutables, no puedo simplemente guardar su estado en el Componente 1 y reenviarlo, ¿verdad? Y sí, he leído sobre redux, pero no quiero usarlo. Espero que sea posible resolverlo solo con reaccionar. ¿Me equivoco?

Iván
Para la comunicación entre padres e hijos, debe pasar una función que establezca el estado de padre a hijo, como esta
class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
}
handler() {
this.setState({
someVar: 'some value'
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}
De esta forma, el hijo puede actualizar el estado del padre con la llamada de una función pasada con accesorios.
Pero tendrá que repensar la estructura de sus componentes, porque según tengo entendido, los componentes 5 y 3 no están relacionados.
Una posible solución es envolverlos en un componente de nivel superior que contendrá el estado de los componentes 1 y 3. Este componente establecerá el estado de nivel inferior a través de accesorios.

romano
Encontré la siguiente solución de trabajo para pasar el argumento de la función onClick del elemento secundario al componente principal:
Versión con pasar un método()
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div><button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
var handleToUpdate = this.handleToUpdate.bind(this);
var arg1 = '';
}
handleToUpdate(someArg){
alert('We pass argument from Child to Parent: ' + someArg);
this.setState({arg1:someArg});
}
render() {
var handleToUpdate = this.handleToUpdate;
return (<div>
<ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
Mira JSFiddle
Versión con pasar una función de flecha
//ChildB component
class ChildB extends React.Component {
render() {
var handleToUpdate = this.props.handleToUpdate;
return (<div>
<button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}
//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
}
handleToUpdate = (someArg) => {
alert('We pass argument from Child to Parent: ' + someArg);
}
render() {
return (<div>
<ChildB handleToUpdate = {this.handleToUpdate} /></div>)
}
}
if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}
Mira JSFiddle
Así es como podemos hacerlo con el nuevo useState
gancho. Método: pase la función de cambio de estado como accesorio al componente secundario y haga lo que quiera con la función
import React, {useState} from 'react';
const ParentComponent = () => {
const[state, setState]=useState('');
return(
<ChildConmponent stateChanger={setState} />
)
}
const ChildConmponent = ({stateChanger, ...rest}) => {
return(
<button onClick={() => stateChanger('New data')}></button>
)
}
Quiero agradecer a la respuesta más votada por darme la idea de mi propio problema, básicamente, la variación con la función de flecha y pasar el parámetro del componente secundario:
class Parent extends React.Component {
constructor(props) {
super(props)
// without bind, replaced by arrow func below
}
handler = (val) => {
this.setState({
someVar: val
})
}
render() {
return <Child handler = {this.handler} />
}
}
class Child extends React.Component {
render() {
return <Button onClick = {() => this.props.handler('the passing value')}/ >
}
}
Espero que ayude a alguien.

Estilos mate
Me gusta la respuesta con respecto a pasar funciones. Es una técnica muy práctica.
Por otro lado, también puede lograr esto usando pub/sub o usando una variante, un despachador, como Flujo lo hace. La teoría es súper simple. Haga que el componente 5 envíe un mensaje que el componente 3 está escuchando. Luego, el componente 3 actualiza su estado, lo que activa la nueva representación. Esto requiere componentes con estado, que, según su punto de vista, pueden o no ser un antipatrón. Estoy en contra de ellos personalmente y preferiría que otra cosa esté escuchando los despachos y los cambios de estado desde arriba hacia abajo (Redux hace esto, pero agrega terminología adicional).
import { Dispatcher } from 'flux'
import { Component } from 'React'
const dispatcher = new Dispatcher()
// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
state = {
text: 'foo'
}
componentDidMount() {
dispatcher.register( dispatch => {
if ( dispatch.type === 'change' ) {
this.setState({ text: 'bar' })
}
}
}
render() {
return <h1>{ this.state.text }</h1>
}
}
// Click handler
const onClick = event => {
dispatcher.dispatch({
type: 'change'
})
}
// Component 5 in your example
const StatelessChild = props => {
return <button onClick={ onClick }>Click me</button>
}
Los paquetes de despachador con Flux son muy simples. Simplemente registra las devoluciones de llamadas y las invoca cuando se produce un envío, pasando por los contenidos del envío (en el conciso ejemplo anterior no hay payload
con el envío, simplemente una identificación de mensaje). Puede adaptar esto al pub/sub tradicional (por ejemplo, usando EventEmitter de eventos, o alguna otra versión) muy fácilmente si tiene más sentido para usted.

Pedro Mortensen
Encontré la siguiente solución de trabajo para pasar el argumento de la función onClick del componente secundario al componente principal con un parámetro:
Clase de padres:
class Parent extends React.Component {
constructor(props) {
super(props)
// Bind the this context to the handler function
this.handler = this.handler.bind(this);
// Set some state
this.state = {
messageShown: false
};
}
// This method will be sent to the child component
handler(param1) {
console.log(param1);
this.setState({
messageShown: true
});
}
// Render the child component and set the action property with the handler as value
render() {
return <Child action={this.handler} />
}}
Clase infantil:
class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component */}
<Button onClick={this.props.action.bind(this,param1)} />
</div>
)
} }

Pedro Mortensen
Siempre que necesite comunicarse entre un niño y el padre en cualquier nivel inferior, entonces es mejor hacer uso de contexto. En el componente padre, defina el contexto que puede ser invocado por el hijo, como por ejemplo:
En el componente padre, en su caso componente 3,
static childContextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
getChildContext() {
return {
parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
};
}
parentMethod(parameter_from_child){
// Update the state with parameter_from_child
}
Ahora, en el componente secundario (componente 5 en su caso), solo dígale a este componente que quiere usar el contexto de su padre.
static contextTypes = {
parentMethod: React.PropTypes.func.isRequired
};
render() {
return(
<TouchableHighlight
onPress = {() => this.context.parentMethod(new_state_value)}
underlayColor="gray" >
<Text> update state in parent component </Text>
</TouchableHighlight>
)}
Puede encontrar el proyecto Demo en este repositorio de GitHub.
muy fácil: pase la función padre-setState-Function a través de la propiedad al componente secundario:{this.setState(p)}} /> En el componente secundario, llámelo a través de this.props. setState({miObj,…});
–Marcel Ennix
8 mayo 2018 a las 21:47
<MyChildComponent setState={(s,c)=>{this.setState(s, c)}} />
si vas a usar este truco, asegúrate de admitir la devolución de llamada.– Barkermn01
10/04/2019 a las 14:50
Pasar una devolución de llamada para establecer el estado de los padres es una práctica realmente mala que podría generar problemas de mantenimiento. Rompe la encapsulación y hace que los componentes 2, 4 y 5 estén estrechamente acoplados al 1. Si sigue este camino, no podrá reutilizar ninguno de estos componentes secundarios en ningún otro lugar. Es mejor que tenga accesorios específicos para que los componentes secundarios puedan desencadenar eventos siempre que suceda algo, luego el componente principal manejaría ese evento correctamente.
– Pato Loco
4 de octubre de 2019 a las 13:51
@MarcelEnnix, ¿por qué los corchetes alrededor
this.setState(p)
? Probé sin ellos y parece funcionar (soy muy nuevo en React)– Biganón
10 de abril de 2020 a las 15:12
@Biganon Hmmm. Tienes razón. Lo siento por esos 2 caracteres adicionales 🙂 Tal vez sea porque me gustan mucho los corchetes rizados. Tengo una camiseta impresa con esta declaración ^^
–Marcel Ennix
12 de abril de 2020 a las 6:48