Como atualizar o estado do pai no React?

Minha estrutura é a seguinte:

Component 1 - |- Component 2 - - |- Component 4 - - - |- Component 5 Component 3 

O componente 3 deve exibir alguns dados dependendo do estado do componente 5. Como os suportes são imutáveis, não posso simplesmente salvar seu estado no componente 1 e encaminhá-lo, certo? E sim, eu li sobre o redux, mas não quero usá-lo. Espero que seja possível resolvê-lo apenas com reagir. Estou errado?

Para comunicação entre pais e filhos você deve passar uma function definindo o estado de pai para filho, assim

 class Parent extends React.Component { constructor(props) { super(props) this.handler = this.handler.bind(this) } handler(e) { e.preventDefault() this.setState({ someVar: someValue }) } render() { return  } } class Child extends React.Component { render() { return  } } 

Eu encontrei a seguinte solução de trabalho para passar o argumento de function onClick de filho para o componente pai:

Versão com a passagem de um método ()

 //ChildB component class ChildB extends React.Component { render() { var handleToUpdate = this.props.handleToUpdate; return (
) } } //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 (
) } } if(document.querySelector("#demo")){ ReactDOM.render( , document.querySelector("#demo") ); }

Olhe para JSFIDDLE

Versão com passagem de uma function de seta

 //ChildB component class ChildB extends React.Component { render() { var handleToUpdate = this.props.handleToUpdate; return (
) } } //ParentA component class ParentA extends React.Component { constructor(props) { super(props); } handleToUpdate = (someArg) => { alert('We pass argument from Child to Parent: ' + someArg); } render() { return (
) } } if(document.querySelector("#demo")){ ReactDOM.render( , document.querySelector("#demo") ); }

Olhe para JSFIDDLE

Eu gosto da resposta sobre passar funções, é uma técnica muito útil.

Por outro lado, você também pode conseguir isso usando pub / sub ou usando uma variante, um dispatcher, como o Flux faz. A teoria é super simples, faça com que o componente 5 envie uma mensagem que o componente 3 esteja ouvindo. O componente 3 atualiza seu estado que aciona a nova renderização. Isso requer componentes com estado, o que, dependendo do seu ponto de vista, pode ou não ser um antipadrão. Eu sou contra eles pessoalmente e prefiro que algo mais esteja escutando os despachos e mude o estado de cima para baixo (o Redux faz isso, mas adiciona uma terminologia 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 

{ this.state.text }

} } // Click handler const onClick = event => { dispatcher.dispatch({ type: 'change' }) } // Component 5 in your example const StatelessChild = props => { return }

O dispatcher empacota com o Flux é muito simples, ele simplesmente registra callbacks e invoca-os quando qualquer despacho ocorre, passando pelo conteúdo no despacho (no exemplo conciso acima não há payload com o dispatch, simplesmente um id de mensagem). Você poderia adaptar isso ao pub / sub tradicional (por exemplo, usando o EventEmitter de events, ou alguma outra versão) muito facilmente se isso faz mais sentido para você.

Eu encontrei a seguinte solução de trabalho para passar o argumento de function onClick de filho para o componente pai com param:

class pai:

 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  }} 

class infantil:

 class Child extends React.Component { render() { return ( 
{/* The button will execute the handler function set by the parent component */}
) } }

Sempre que você precisar se comunicar entre filho para pai em qualquer nível abaixo, então é melhor usar o contexto . No componente pai, defina o contexto que pode ser chamado pelo filho, como

No componente pai no seu componente de caso 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 } 

Agora, no componente filho (componente 5 no seu caso), basta informar a este componente que ele deseja usar o contexto de seu pai.

  static contextTypes = { parentMethod: React.PropTypes.func.isRequired }; render(){ return( this.context.parentMethod(new_state_value)} underlayColor='gray' >  update state in parent component   )} 

você pode encontrar o projeto de demonstração no repo

 
this.setState({showChart: true})} />
{console.log(this.props)}
Try this example to write inline setState, it avoids creating another function.