2016-02-21 10 views
91

Meine Struktur sieht wie folgt aus:Wie aktualisiert man den Elternstatus in React?

Component 1 

- |- Component 2 


- - |- Component 4 


- - - |- Component 5 

Component 3 

Komponente 3 sollte je nach Zustand der Komponente einige Daten anzuzeigen 5. Da Requisiten unveränderlich sind, kann ich einfach es ist Zustand in Komponente 1 und übermittelt ihn nicht retten, rechts ? Und ja, ich habe über redux gelesen, möchte es aber nicht verwenden. Ich hoffe, dass es möglich ist, es nur mit der Reaktion zu lösen. Liege ich falsch?

Antwort

192

Für Eltern-Kind-Kommunikation Sie eine Funktion übergeben, sollte den Zustand von Eltern auf das Kind, wie diese

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 <Child handler = {this.handler} /> 
 
    } 
 
} 
 

 
class Child extends React.Component { 
 
    render() { 
 
    return <Button onClick = {this.props.handler}/ > 
 
    } 
 
}

diese Weise das Kind Einstellung der staatlichen Mutter aktualisieren können mit dem Aufruf von eine Funktion mit Requisiten übergeben.

Aber Sie müssen die Struktur Ihrer Komponenten überdenken, weil, wie ich verstehe, Komponenten 5 und 3 nicht verwandt sind.

Eine mögliche Lösung besteht darin, sie in eine Komponente auf höherer Ebene zu verpacken, die den Status von Komponente 1 und 3 enthält. Diese Komponente setzt den niedrigeren Status durch Requisiten.

+1

warum brauchen Sie this.handler = this.handler.bind (this) und nicht nur die Handler-Funktion, die den Status setzt? – chemook78

+7

@ chemook78 in ES6 React-Klassen-Methoden binden nicht automatisch an die Klasse. Wenn wir 'this.handler = this.handler.bind (this)' 'im Konstruktor nicht hinzufügen, verweist' this' innerhalb der 'handler'-Funktion auf die Funktion closure, nicht auf die Klasse. Wenn Sie nicht alle Ihre Funktionen im Konstruktor binden möchten, gibt es zwei weitere Möglichkeiten, dies mit Pfeilfunktionen zu erledigen. Sie könnten den Click-Handler einfach als 'onClick = {() => this.setState (...)}' schreiben, oder Sie könnten Property-Initialisierer zusammen mit Pfeilfunktionen verwenden, wie hier beschrieben https://babeljs.io/blog/ 2015/06/07/react-on-es6-plus unter "Pfeilfunktionen" – Ivan

+1

Hier ein Beispiel dafür in Aktion: http://plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview – Tamb

6

Ich mag die Antwort in Bezug auf die Weitergabe von Funktionen, es ist eine sehr praktische Technik.

Auf der anderen Seite können Sie dies auch mit pub/sub erreichen oder mit einer Variante, einem Dispatcher, wie Flux. Die Theorie ist super einfach, die Komponente 5 sendet eine Nachricht, auf die die Komponente 3 hört. Die Komponente 3 aktualisiert dann ihren Zustand, der das erneute Rendern auslöst. Dies erfordert Stateful-Komponenten, die je nach Sichtweise ein Anti-Pattern sein können oder auch nicht. Ich bin gegen sie persönlich und würde lieber, dass etwas anderes auf Sendungen wartet und Status von ganz oben ändert (Redux tut dies, fügt aber zusätzliche Terminologie hinzu).

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

Der Dispatcher Bündel mit Flußmittel ist sehr einfach, es ist einfach Rückrufe registriert und ruft sie, wenn ein Versand erfolgt, auf dem Versand durch den Inhalt Passing (in dem obigen terse Beispiel keine payload mit dem Versand ist, einfach eine Nachrichten-ID). Sie können dies an traditionelle Pub/Sub anpassen (z. B. den EventEmitter aus Ereignissen oder einer anderen Version verwenden), wenn dies für Sie sinnvoller ist.

+0

Meine Reacts-Komponenten laufen im Browser wie in einem offiziellen Tutorial (https://facebook.github.io/react/docs/tutorial.html) Ich habe versucht, Flux mit browserify zu integrieren, aber der Browser sagt, dass der Dispatcher ist nicht gefunden :( – wklm

+2

Die Syntax, die ich verwendet habe, war ES2016 Modul-Syntax, die Transpilation erfordert (ich verwende [Babel] (https://babeljs.io/), aber es gibt andere, die [babelify] (https: //www.npmjs .com/package/babelify) transform kann mit browserify verwendet werden, es transpiliert nach 'var Dispatcher = require ('flux') .Dispatcher' –

1

Wenn Sie jemals auf einer beliebigen Ebene zwischen Kind und Eltern kommunizieren müssen, ist es besser Kontext zu verwenden. In übergeordneter Komponente den Kontext definieren, die durch das Kind

in übergeordneter Komponente in Ihrem Fall Komponente wie

aufgerufen werden kann 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 
} 

Jetzt in Kind (Komponente 5 in Ihrem Fall), teilen Sie einfach diese Komponente, die es Kontext seiner Eltern verwenden möchten.

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

können Sie Demo-Projekt finden Sie unter repo

8

ich die folgende Arbeitslösung gefunden onClick Funktion Argument von Kind auf die übergeordnete Komponente zu übergeben:

//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") 
    ); 
} 

Look at JSFIDDLE

+0

Dieses ist gut! Könnten Sie dieses Stück erklären:' 'Warum musste wieder gebunden werden? – Dane

3

Ich fand die folgende funktionierende Lösung, um onClick Funktion Argument von Kind zu t zu übergeben er übergeordnete Komponente mit param:

Elternklasse:

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

Kind Klasse:

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> 
    ) 
} } 
+0

Kann jemand sagen, ob das eine akzeptable Lösung ist (besonders daran interessiert, den Parameter wie vorgeschlagen zu übergeben). – ilans

0
<Footer 
    action={()=>this.setState({showChart: true})} 
/> 

<footer className="row"> 
    <button type="button" onClick={this.props.action}>Edit</button> 
    {console.log(this.props)} 
</footer> 

Try this example to write inline setState, it avoids creating another function. 
Verwandte Themen