¿Cómo puedo actualizar state.item[1] en el estado usando setState?
Estoy creando una aplicación donde el usuario puede diseñar su propio formulario. Por ejemplo, especifique el nombre del campo y los detalles de qué otras columnas deben incluirse.
El componente está disponible como JSFiddle .
Mi estado inicial se ve así:
var DynamicForm = React.createClass({
getInitialState: function() {
var items = {};
items[1] = { name: 'field 1', populate_at: 'web_start',
same_as: 'customer_name',
autocomplete_from: 'customer_name', title: '' };
items[2] = { name: 'field 2', populate_at: 'web_end',
same_as: 'user_name',
autocomplete_from: 'user_name', title: '' };
return { items };
},
render: function() {
var _this = this;
return (
<div>
{ Object.keys(this.state.items).map(function (key) {
var item = _this.state.items[key];
return (
<div>
<PopulateAtCheckboxes this={this}
checked={item.populate_at} id={key}
populate_at={data.populate_at} />
</div>
);
}, this)}
<button onClick={this.newFieldEntry}>Create a new field</button>
<button onClick={this.saveAndContinue}>Save and Continue</button>
</div>
);
}
Quiero actualizar el estado cuando el usuario cambia cualquiera de los valores, pero me resulta difícil apuntar al objeto correcto:
var PopulateAtCheckboxes = React.createClass({
handleChange: function (e) {
item = this.state.items[1];
item.name = 'newName';
items[1] = item;
this.setState({items: items});
},
render: function() {
var populateAtCheckbox = this.props.populate_at.map(function(value) {
return (
<label for={value}>
<input type="radio" name={'populate_at'+this.props.id} value={value}
onChange={this.handleChange} checked={this.props.checked == value}
ref="populate-at"/>
{value}
</label>
);
}, this);
return (
<div className="populate-at-checkboxes">
{populateAtCheckbox}
</div>
);
}
});
¿ Cómo debo elaborar this.setState
para que se actualice items[1].name
?
Así es como puedes hacerlo sin bibliotecas auxiliares:
handleChange: function (e) {
// 1. Make a shallow copy of the items
let items = [...this.state.items];
// 2. Make a shallow copy of the item you want to mutate
let item = {...items[1]};
// 3. Replace the property you're intested in
item.name = 'newName';
// 4. Put it back into our array. N.B. we *are* mutating the array here,
// but that's why we made a copy first
items[1] = item;
// 5. Set the state to our new copy
this.setState({items});
},
Puedes combinar los pasos 2 y 3 si quieres:
let item = {
...items[1],
name: 'newName'
}
O puedes hacer todo en una sola línea:
this.setState(({items}) => ({
items: [
...items.slice(0,1),
{
...items[1],
name: 'newName',
},
...items.slice(2)
]
}));
Nota: hice items
una matriz. OP usó un objeto. Sin embargo, los conceptos son los mismos.
Puedes ver lo que está pasando en tu terminal/consola:
❯ node
> items = [{name:'foo'},{name:'bar'},{name:'baz'}]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> clone = [...items]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> item1 = {...clone[1]}
{ name: 'bar' }
> item1.name = 'bacon'
'bacon'
> clone[1] = item1
{ name: 'bacon' }
> clone
[ { name: 'foo' }, { name: 'bacon' }, { name: 'baz' } ]
> items
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ] // good! we didn't mutate `items`
> items === clone
false // these are different objects
> items[0] === clone[0]
true // we don't need to clone items 0 and 2 because we're not mutating them (efficiency gains!)
> items[1] === clone[1]
false // this guy we copied
Podrías usar el update
asistente de inmutabilidad para esto :
this.setState({
items: update(this.state.items, {1: {name: {$set: 'updated field name'}}})
})
O si no le importa poder detectar cambios en este elemento en un shouldComponentUpdate()
método de ciclo de vida usando ===
, puede editar el estado directamente y forzar que el componente se vuelva a representar; esto es efectivamente lo mismo que la respuesta de @limelights, ya que es sacar un objeto del estado y editarlo.
this.state.items[1].name = 'updated field name'
this.forceUpdate()
Adición posterior a la edición:
Consulte la lección Comunicación de componentes simples de react-training para ver un ejemplo de cómo pasar una función de devolución de llamada de un componente principal que posee el estado a un componente secundario que necesita desencadenar un cambio de estado.