tipos react organizar funcionales entre entender crear comunicacion componentes componente como reactjs siblings

reactjs - organizar - tipos de componentes react



¿Cómo configuro fácilmente el estado de los componentes hermanos en React? (3)

El componente principal debe pasar una devolución de llamada a los secundarios, y cada niño activará esa devolución de llamada cuando cambie su estado. En realidad, podría mantener todo el estado en el padre, usándolo como un único punto de verdad, y pasar el valor "seleccionado" a cada hijo como prop.

En ese caso, el niño podría verse así:

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

No tiene estado, simplemente dispara una onToggle llamada onToggle cuando se hace clic. El padre se vería así:

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

Mantiene una serie de selecciones en el estado y cuando maneja la devolución de llamada de un hijo, usa setState para volver a renderizar a los niños pasando su estado en la propiedad selected a cada hijo.

Puedes ver un ejemplo de esto aquí:

https://jsfiddle.net/fth25erj/

Tengo los principios de un componente de lista pulsable que servirá para impulsar un elemento de selección. Como puede ver a continuación, al hacer onClick en ListItem , ListItem el estado de un elemento secundario ( ListItem en este caso) a los padres ( SelectableList , y CustomSelect component). Esto está funcionando bien. Sin embargo, lo que también me gustaría hacer es cambiar el estado de los componentes hermanos (los otros ListItems) para que pueda alternar sus estados seleccionados cuando se hace clic en uno de los ListItems.

En este momento, simplemente estoy usando document.querySelectorAll(''ul.cs-select li) para capturar los elementos y cambiar la clase a seleccionada cuando no coincide con el índice del ListItem el que se hizo clic. Esto funciona - hasta cierto punto. Sin embargo, después de unos pocos clics, React (solo por parte del cliente JS) no ha actualizado el estado del componente, y las cosas comienzan a descomponerse. Lo que me gustaría hacer es cambiar this.state.isSelected de los this.state.isSelected de la lista de hermanos, y usar este estado para actualizar el componente SelectableList. ¿Podría alguien ofrecer una mejor alternativa a lo que he escrito a continuación?

var React = require(''react''); var SelectBox = require(''./select-box''); var ListItem = React.createClass({ getInitialState: function() { return { isSelected: false }; }, toggleSelected: function () { if (this.state.isSelected == true) { this.setState({ isSelected: false }) } else { this.setState({ isSelected: true }) } }, handleClick: function(listItem) { this.toggleSelected(); this.props.onListItemChange(listItem.props.value); var unboundForEach = Array.prototype.forEach, forEach = Function.prototype.call.bind(unboundForEach); forEach(document.querySelectorAll(''ul.cs-select li''), function (el) { // below is trying to // make sure that when a user clicks on a list // item in the SelectableList, then all the *other* // list items get class="selected" removed. // this works for the first time that you move through the // list clicking the other items, but then, on the second // pass through, starts to fail, requiring *two clicks* before the // list item is selected again. // maybe there''s a better more "reactive" method of doing this? if (el.dataset.index != listItem.props.index && el.classList.contains(''selected'') ) { el.classList.remove(''selected''); } }); }, render: function() { return ( <li ref={"listSel"+this.props.key} data-value={this.props.value} data-index={this.props.index} className={this.state.isSelected == true ? ''selected'' : '''' } onClick={this.handleClick.bind(null, this)}> {this.props.content} </li> ); } }); var SelectableList = React.createClass({ render: function() { var listItems = this.props.options.map(function(opt, index) { return <ListItem key={index} index={index} value={opt.value} content={opt.label} onListItemChange={this.props.onListItemChange.bind(null, index)} />; }, this); return <ul className="cs-select">{ listItems }</ul>; } }) var CustomSelect = React.createClass({ getInitialState: function () { return { selectedOption: '''' } }, handleListItemChange: function(listIndex, listItem) { this.setState({ selectedOption: listItem.props.value }) }, render: function () { var options = [{value:"One", label: "One"},{value:"Two", label: "Two"},{value:"Three", label: "Three"}]; return ( <div className="group"> <div className="cs-select"> <SelectableList options={options} onListItemChange={this.handleListItemChange} /> <SelectBox className="cs-select" initialValue={this.state.selectedOption} fieldName="custom-select" options={options}/> </div> </div> ) } }) module.exports = CustomSelect;


El siguiente código me ayuda a configurar la comunicación entre dos hermanos. La configuración se realiza en su padre durante las llamadas render () y 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> ); } }


Otra estrategia para la comunicación entre hermanos es usar un patrón de observador.

El patrón del observador es un patrón de diseño de software en el que un objeto puede enviar mensajes a varios otros objetos.

No se requiere una relación entre hermanos o padres e hijos para usar esta estrategia.

En el contexto de React, esto significaría que algunos componentes se suscriben para recibir mensajes particulares y otros componentes publican mensajes para esos suscriptores.

Los componentes normalmente se suscribirán en el método componentDidMount y se cancelarán en el método componentWillUnmount.

Aquí hay 4 bibliotecas que implementan el patrón de observador. Las diferencias entre ellos son sutiles: EventEmitter es el más popular.

  • PubSubJS : "una biblioteca de publicación / suscripción basada en temas escrita en JavaScript".
  • EventEmitter : "JavaScript con eventos para el navegador". En realidad, es una implementación de una biblioteca que ya existe como parte del núcleo de nodejs, pero para el navegador.
  • MicroEvent.js : "microlibrería de emisores de eventos - 20 líneas - para nodo y navegador"
  • mobx : "Administración de estado simple y escalable".

Tomado de: 8 estrategias sin flujo para la comunicación de componentes React, que también es una gran lectura en general.