2015-06-15 5 views
13

Ich habe die Anfänge einer anklickbaren List-Komponente, die dazu dienen wird, ein Select-Element zu steuern. Wie Sie aus der unten onClick des ListItem sehen können, bin ich vorbei, den Zustand eines Kindes Element (ListItem in diesem Fall) zu den Eltern (SelectableList und CustomSelect Komponente). Das funktioniert gut. Allerdings möchte ich auch den Zustand der Geschwister Komponenten (die anderen ListItems) ändern, so dass ich ihre ausgewählten Zustände umschalten kann, wenn eines der ListItems geklickt wird.Wie kann ich den Zustand von Geschwisterkomponenten in React einfach einstellen?

Im Moment verwende ich einfach document.querySelectorAll('ul.cs-select li), um die Elemente zu greifen und die Klasse zu selektieren, wenn sie nicht mit dem Index der angeklickten ListItem übereinstimmt. Das funktioniert - in gewissem Maße. Nach ein paar Klicks wurde der Status der Komponente jedoch nicht von React aktualisiert (nur von JS auf der Clientseite), und die Dinge beginnen zu brechen. Ich möchte die this.state.isSelected der Geschwisterlistenelemente ändern und diesen Status verwenden, um die SelectableList-Komponente zu aktualisieren. Kann jemand eine bessere Alternative zu dem anbieten, was ich unten geschrieben habe?

Antwort

15

Die übergeordnete Komponente sollte einen Rückruf an die untergeordneten Elemente übergeben, und jedes untergeordnete Element würde diesen Rückruf auslösen, wenn sich der Status ändert. Du könntest den ganzen Staat im Elternteil halten und ihn als einen einzigen Punkt der Wahrheit benutzen und den "ausgewählten" Wert an jedes Kind als eine Stütze weitergeben.

In diesem Fall könnte das Kind wie folgt aussehen:

var Child = React.createClass({ 
    onToggle: function() { 
     this.props.onToggle(this.props.id, !this.props.selected); 
    }, 

    render: function() { 
     return <button onClick={this.onToggle}>Toggle {this.props.label} - {this.props.selected ? 'Selected!' : ''}!</button>; 
    } 
}); 

Es hat sich kein Staat, es ist nur ein onToggle Rückruf ausgelöst wird, wenn darauf geklickt. Die Mutter würde wie folgt aussehen:

var Parent = React.createClass({ 
    getInitialState: function() { 
     return { 
      selections: [] 
     }; 
    }, 
    onChildToggle: function(id, selected) { 
     var selections = this.state.selections; 

     selections[id] = selected; 

     this.setState({ 
      selections: selections 
     }); 
    }, 

    buildChildren: function(dataItem) { 
     return <Child 
      id={dataItem.id} 
      label={dataItem.label} 
      selected={this.state.selections[dataItem.id]} 
      onToggle={this.onChildToggle} /> 
    }, 

    render: function() { 
     return <div>{this.props.data.map(this.buildChildren)}</div> 
    } 
}); 

Es hält eine Reihe von Auswahlmöglichkeiten in Zustand und wenn er den Rückruf von einem Kind behandelt, benutzt es setState, um die Kinder wieder zu machen durch seinen Zustand nach unten in dem selected prop vorbei zu jedem Kind.

Sie können ein funktionierendes Beispiel dafür hier sehen:

https://jsfiddle.net/fth25erj/

+0

Danke Colin. Sieht so aus, als könnte ich das schaffen. Braucht nur ein wenig Logik in '' onChildToggle() '' ', um es exklusiv auszuwählen, anstatt eine Mehrfachauswahloption. –

+0

Und wenn es eine einzige Auswahl ist, speichern Sie einfach einen einzelnen Wert, der das ausgewählte Element angibt. Dies ist normalerweise der Index des ausgewählten Datenelements oder dessen ID. Sie können dann 'selected = {this.state.selected === index}' oder 'selected = {this.state.selected === dataItem.id}' auswählen – FakeRainBrigand

0

Der folgende Code hilft mir zwischen zwei Geschwistern Setup Kommunikation. Die Einrichtung erfolgt in ihren Eltern während der Aufrufe von render() und componentDidMount().

class App extends React.Component<IAppProps, IAppState> { 
    private _navigationPanel: NavigationPanel; 
    private _mapPanel: MapPanel; 

    constructor() { 
     super(); 
     this.state = {}; 
    } 

    // `componentDidMount()` is called by ReactJS after `render()` 
    componentDidMount() { 
     // Pass _mapPanel to _navigationPanel 
     // It will allow _navigationPanel to call _mapPanel directly 
     this._navigationPanel.setMapPanel(this._mapPanel); 
    } 

    render() { 
     return (
      <div id="appDiv" style={divStyle}> 
       // `ref=` helps to get reference to a child during rendering 
       <NavigationPanel ref={(child) => { this._navigationPanel = child; }} /> 
       <MapPanel ref={(child) => { this._mapPanel = child; }} /> 
      </div> 
     ); 
    } 
}