Básicamente, estoy tratando de hacer que las pestañas reaccionen, pero con algunos problemas.
Aquí está el archivo page.jsx
<RadioGroup>
<Button title="A" />
<Button title="B" />
</RadioGroup>
Al hacer clic en el botón A, las necesidades de componentes RadioGroup para deseleccionar el botón B .
"Seleccionado" solo significa un className de un estado o propiedad
Aquí está RadioGroup.jsx
:
module.exports = React.createClass({
onChange: function( e ) {
// How to modify children properties here???
},
render: function() {
return (<div onChange={this.onChange}>
{this.props.children}
</div>);
}
});
La fuente de Button.jsx
realmente no importa, tiene un botón de radio HTML regular que activa el onChange
evento DOM nativo
El flujo esperado es:
- Haga clic en el botón "A"
- El botón "A" activa onChange, evento DOM nativo, que se propaga a RadioGroup
- Se llama al oyente de RadioGroup onChange
- RadioGroup necesita de-seleccione el botón B . Esta es mi pregunta.
Aquí está el problema principal que estoy encontrando: no puedo moverme <Button>
aRadioGroup
, porque la estructura de esto es tal que los niños son arbitrarios . Es decir, el marcado podría ser
<RadioGroup>
<Button title="A" />
<Button title="B" />
</RadioGroup>
o
<RadioGroup>
<OtherThing title="A" />
<OtherThing title="B" />
</RadioGroup>
Probé algunas cosas.
Intentar: En RadioGroup
controlador onChange 's:
React.Children.forEach( this.props.children, function( child ) {
// Set the selected state of each child to be if the underlying <input>
// value matches the child's value
child.setState({ selected: child.props.value === e.target.value });
});
Problema:
Invalid access to component property "setState" on exports at the top
level. See react-warning-descriptors . Use a static method
instead: <exports />.type.setState(...)
Intentar: En RadioGroup
controlador onChange 's:
React.Children.forEach( this.props.children, function( child ) {
child.props.selected = child.props.value === e.target.value;
});
Problema: no pasa nada, incluso yo le doy Button
un componentWillReceiveProps
método a la clase
Intento: intenté pasar algún estado específico del padre a los hijos, por lo que puedo actualizar el estado del padre y hacer que los hijos respondan automáticamente. En la función de renderizado de RadioGroup:
React.Children.forEach( this.props.children, function( item ) {
this.transferPropsTo( item );
}, this);
Problema:
Failed to make request: Error: Invariant Violation: exports: You can't call
transferPropsTo() on a component that you don't own, exports. This usually
means you are calling transferPropsTo() on a component passed in as props
or children.
Mala solución n. ° 1 : use el método react-addons.js cloneWithProps para clonar a los niños en el tiempo de renderizado RadioGroup
para poder pasarles propiedades
Mala solución n. ° 2 : implementar una abstracción alrededor de HTML / JSX para que pueda pasar las propiedades dinámicamente (mátame):
<RadioGroup items=[
{ type: Button, title: 'A' },
{ type: Button, title: 'B' }
]; />
Y luego, RadioGroup
construya dinámicamente estos botones.
Esta pregunta no me ayuda porque necesito hacer que mis hijos sin saber qué son
RadioGroup
saber que necesita reaccionar ante un evento de sus hijos arbitrarios? Necesariamente tiene que saber algo sobre sus hijos.React.addons.cloneWithProps
y pase los nuevos accesorios que le gustaría que tuviera.props
son inmutables, por lo que está creando un nuevo hash, fusionándolo con los accesorios actuales y pasando el nuevo hashprops
a una nueva instancia del componente hijo.Respuestas:
No estoy seguro de por qué dice que usar
cloneWithProps
es una mala solución, pero aquí hay un ejemplo de trabajo que lo usa.var Hello = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); var App = React.createClass({ render: function() { return ( <Group ref="buttonGroup"> <Button key={1} name="Component A"/> <Button key={2} name="Component B"/> <Button key={3} name="Component C"/> </Group> ); } }); var Group = React.createClass({ getInitialState: function() { return { selectedItem: null }; }, selectItem: function(item) { this.setState({ selectedItem: item }); }, render: function() { var selectedKey = (this.state.selectedItem && this.state.selectedItem.props.key) || null; var children = this.props.children.map(function(item, i) { var isSelected = item.props.key === selectedKey; return React.addons.cloneWithProps(item, { isSelected: isSelected, selectItem: this.selectItem, key: item.props.key }); }, this); return ( <div> <strong>Selected:</strong> {this.state.selectedItem ? this.state.selectedItem.props.name : 'None'} <hr/> {children} </div> ); } }); var Button = React.createClass({ handleClick: function() { this.props.selectItem(this); }, render: function() { var selected = this.props.isSelected; return ( <div onClick={this.handleClick} className={selected ? "selected" : ""} > {this.props.name} ({this.props.key}) {selected ? "<---" : ""} </div> ); } }); React.renderComponent(<App />, document.body);
Aquí hay un jsFiddle que lo muestra en acción.
EDITAR : aquí hay un ejemplo más completo con contenido de pestaña dinámica: jsFiddle
fuente
this
. ¿Existe alguna ventaja real, además de haber usado React?Los botones deben ser apátridas. En lugar de actualizar las propiedades de un botón de forma explícita, simplemente actualice el estado del propio grupo y vuelva a renderizar. El método de renderizado del Grupo debería entonces mirar su estado al renderizar los botones y pasar "activo" (o algo) solo al botón activo.
fuente
Tal vez la mía sea una solución extraña, pero ¿por qué no usar el patrón de observador?
module.exports = React.createClass({ buttonSetters: [], regSetter: function(v){ buttonSetters.push(v); }, handleChange: function(e) { // ... var name = e.target.name; //or name this.buttonSetters.forEach(function(v){ if(v.name != name) v.setState(false); }); }, render: function() { return ( <div> <Button title="A" regSetter={this.regSetter} onChange={handleChange}/> <Button title="B" regSetter={this.regSetter} onChange={handleChange} /> </div> ); });
module.exports = React.createClass({ onChange: function( e ) { // How to modify children properties here??? }, componentDidMount: function() { this.props.regSetter({name:this.props.title,setState:this.setState}); }, onChange:function() { this.props.onChange(); }, render: function() { return (<div onChange={this.onChange}> <input element .../> </div>); } });
tal vez necesites algo más, pero esto me pareció muy poderoso,
Realmente prefiero usar un modelo externo que proporcione métodos de registro de observadores para varias tareas
fuente
Button.jsx
?onChange()
yonChange(e)
Cree un objeto que actúe como intermediario entre el padre y el hijo. Este objeto contiene referencias de funciones tanto en el padre como en el hijo. Luego, el objeto se pasa como un accesorio del padre al hijo. Ejemplo de código aquí:
https://stackoverflow.com/a/61674406/753632
fuente