reactjs - examples - react logo
Reactjs: ¿cómo modificar el estado del componente dinámico infantil o los accesorios del padre? (3)
Básicamente estoy tratando de hacer pestañas en reaccionar, pero con algunos problemas.
Aquí está el archivo page.jsx
<RadioGroup>
<Button title="A" />
<Button title="B" />
</RadioGroup>
Cuando hace clic en el botón A, el componente RadioGroup necesita quitar la selección del 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
realidad no importa, tiene un botón de radio HTML que activa el evento DOM onChange
nativo
El flujo esperado es:
- Haga clic en el botón "A"
- El botón "A" activa el cambio, evento DOM nativo, que sube hasta RadioGroup
- RadioGroup onChange oyente se llama
- RadioGroup necesita desmarcar el botón B. Esta es mi pregunta.
Aquí está el problema principal que estoy enfrentando: no puedo mover <Button>
s en RadioGroup
, 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>
He intentado algunas cosas.
Intento: En el controlador OnChange de RadioGroup:
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(...)
Intento: En el controlador OnChange de RadioGroup:
React.Children.forEach( this.props.children, function( child ) {
child.props.selected = child.props.value === e.target.value;
});
Problema: no pasa nada, incluso le doy a la clase Button
un método componentWillReceiveProps
Intento: Intenté pasar un estado específico del padre a los hijos, por lo que puedo actualizar el estado principal y hacer que los niños respondan automáticamente. En la función de renderización 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 : Utilice el método cloneWithProps react-addons.js para clonar los niños en el momento de la RadioGroup
en RadioGroup
para poder pasarles las propiedades
Mala solución # 2 : Implementar una abstracción alrededor de HTML / JSX para poder pasar las propiedades de forma dinámica (kill me):
<RadioGroup items=[
{ type: Button, title: ''A'' },
{ type: Button, title: ''B'' }
]; />
Y luego en RadioGroup
construye dinámicamente estos botones.
Esta pregunta no me ayuda porque necesito representar a mis hijos sin saber lo que son
Los botones deben ser sin estado. En lugar de actualizar las propiedades de un botón explícitamente, simplemente actualice el estado propio del grupo y vuelva a procesarlo. El método de renderización del Grupo debería entonces ver su estado al renderizar los botones y pasar "activo" (o algo) solo al botón activo.
No estoy seguro de por qué dices 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ñas dinámicas: jsFiddle
Tal vez la mía es una solución extraña, pero ¿por qué no utilizar el patrón de observador?
RadioGroup.jsx
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>
);
});
Button.jsx
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 requieres algo más, pero encontré esto muy poderoso,
Realmente prefiero usar un modelo externo que proporcione métodos de registro de observadores para varias tareas