Javascript 反应:如何使用setState更新状态。项[1]处于状态?
我正在创建一个应用程序,用户可以在其中设计自己的表单。例如,指定字段名称以及应包括哪些其他列的详细信息 该组件作为JSFIDLE提供 我的初始状态如下所示:Javascript 反应:如何使用setState更新状态。项[1]处于状态?,javascript,reactjs,state,Javascript,Reactjs,State,我正在创建一个应用程序,用户可以在其中设计自己的表单。例如,指定字段名称以及应包括哪些其他列的详细信息 该组件作为JSFIDLE提供 我的初始状态如下所示: var DynamicForm = React.createClass({ getInitialState: function() { var items = {}; items[1] = { name: 'field 1', populate_at: 'web_start', same_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>
);
}
this.setState(prevState => {
const newItems = [...prevState.items];
newItems[index].name = newName;
return {items: newItems};
})
var DynamicForm=React.createClass({
getInitialState:函数(){
变量项={};
项[1]={name:'field 1',填充到:'web_start',
与“客户名称”相同,
自动完成来自:客户名称,标题:'};
项[2]={name:'field 2',填充到:'web_end',
与“用户名”相同,
自动完成来自:用户名,标题:'};
返回{items};
},
render:function(){
var_this=这个;
返回(
{Object.keys(this.state.items).map(函数(键){
var item=_this.state.items[key];
返回(
);
},这个)}
创建一个新字段
保存并继续
);
}
我想在用户更改任何值时更新状态,但我很难找到正确的对象:
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>
);
}
});
var populateacheckboxs=React.createClass({
handleChange:函数(e){
item=此.state.items[1];
item.name='newName';
项目[1]=项目;
this.setState({items:items});
},
render:function(){
var populateAtCheckbox=this.props.populate_at.map(函数(值)){
返回(
{value}
);
},这个);
返回(
{populateacheckbox}
);
}
});
我应该如何制作
this.setState
以使其更新项[1].name
?首先获取所需项,更改该对象上所需的内容并将其设置回状态。
如果使用键控对象,则仅通过在getInitialState
中传递对象来使用状态的方式将更容易
handleChange: function (e) {
item = this.state.items[1];
item.name = 'newName';
items[1] = item;
this.setState({items: items});
}
您可以使用:
或者,如果您不关心使用==
在shouldComponentUpdate()
生命周期方法中检测对此项的更改,则可以直接编辑状态并强制组件重新渲染-这实际上与@limelights的回答相同,因为它将对象拉出状态并对其进行编辑
this.state.items[1].name = 'updated field name'
this.forceUpdate()
编辑后添加:
查看中的课程,了解如何将回调函数从持有状态的父组件传递到需要触发状态更改的子组件。使用
handleChange
上的事件找出已更改的元素,然后对其进行更新。为此,您可能需要更改某些属性来标识它和u更新它
请参阅fiddle,试试这个,它肯定会起作用,其他情况我试过了,但没有起作用
import _ from 'lodash';
this.state.var_name = _.assign(this.state.var_name, {
obj_prop: 'changed_value',
});
走错了路!
handleChange = (e) => {
const { items } = this.state;
items[1].name = e.target.value;
// update state
this.setState({
items,
});
};
正如许多优秀开发人员在评论中指出的那样:改变状态是错误的!
我花了一段时间才弄明白这一点。上面的方法有效,但它会削弱React的功能。例如,componentDidUpdate
不会将其视为更新,因为它是直接修改的
因此,正确的方法是:
handleChange = (e) => {
this.setState(prevState => ({
items: {
...prevState.items,
[prevState.items[1].name]: e.target.value,
},
}));
};
如何创建另一个组件(用于需要进入阵列的对象)并将以下内容作为道具传递
这里{index}可以根据使用此子对象窗体的位置传入
setSubObjectData可以是这样的
setSubObjectData: function(index, data){
var arrayFromParentObject= <retrieve from props or state>;
var objectInArray= arrayFromParentObject.array[index];
arrayFromParentObject.array[index] = Object.assign(objectInArray, data);
}
setSubObjectData:函数(索引、数据){
var arrayFromParentObject=;
var objectInArray=arrayFromParentObject.array[index];
arrayFromParentObject.array[index]=Object.assign(objectInArray,数据);
}
在子对象窗体中,可以在数据更改时调用this.props.setData,如下所示
<input type="text" name="name" onChange={(e) => this.props.setData(this.props.objectIndex,{name: e.target.value})}/>
this.props.setData(this.props.objectIndex,{name:e.target.value})}/>
我将移动函数句柄更改并添加索引参数
handleChange: function (index) {
var items = this.state.items;
items[index].name = 'newName';
this.setState({items: items});
},
到动态表单组件,并将其作为道具传递给PopulateAckBox组件。当您循环项目时,可以包括一个附加计数器(在下面的代码中称为索引),以传递给句柄更改,如下所示
{ Object.keys(this.state.items).map(function (key, index) {
var item = _this.state.items[key];
var boundHandleChange = _this.handleChange.bind(_this, index);
return (
<div>
<PopulateAtCheckboxes this={this}
checked={item.populate_at} id={key}
handleChange={boundHandleChange}
populate_at={data.populate_at} />
</div>
);
}, this)}
{Object.keys(this.state.items).map(函数(键,索引){
var item=_this.state.items[key];
var boundHandleChange=\u this.handleChange.bind(\u this,index);
返回(
);
},这个)}
最后,您可以调用您的更改侦听器,如下所示
<input type="radio" name={'populate_at'+this.props.id} value={value} onChange={this.props.handleChange} checked={this.props.checked == value} ref="populate-at"/>
不要在适当的位置改变状态。这可能会导致意外的结果。我已经吸取了教训!始终使用副本/克隆,
对象。assign()
是一个很好的方法:
item = Object.assign({}, this.state.items[1], {name: 'newName'});
items[1] = item;
this.setState({items: items});
如果只需要更改
数组的一部分
,
您有一个状态设置为的react组件
state = {items: [{name: 'red-one', value: 100}, {name: 'green-one', value: 999}]}
最好将数组中的红色部分更新如下:
const itemIndex = this.state.items.findIndex(i=> i.name === 'red-one');
const newItems = [
this.state.items.slice(0, itemIndex),
{name: 'red-one', value: 666},
this.state.items.slice(itemIndex)
]
this.setState(newItems)
要在React的状态下修改深度嵌套的对象/变量,通常会使用三种方法:vanilla JavaScript的Object.assign
,以及cloneDeep
from
还有很多其他不太受欢迎的第三方lib可以实现这一点,但在这个答案中,我将只介绍这三个选项。此外,还有一些普通的JavaScript方法,比如数组扩展(例如,请参见@mpen的答案),但它们不是非常直观、易于使用并且能够处理所有状态操纵情况
正如无数次在对答案的顶级投票评论中指出的那样,其作者提出了一种状态的直接变异:不要这样做。这是一种普遍存在的反模式反应,不可避免地会导致不必要的后果。学会正确的方法
const itemIndex = this.state.items.findIndex(i=> i.name === 'red-one');
const newItems = [
this.state.items.slice(0, itemIndex),
{name: 'red-one', value: 666},
this.state.items.slice(itemIndex)
]
this.setState(newItems)
state = {
outer: {
inner: 'initial value'
}
}
// given a state
state = {items: [{name: 'Fred', value: 1}, {name: 'Wilma', value: 2}]}
// This will work without mutation as it clones the modified item in the map:
this.state.items
.map(item => item.name === 'Fred' ? {...item, ...{value: 3}} : item)
this.setState(newItems)
const newItems = [...this.state.items];
newItems[item] = value;
this.setState({ items:newItems });
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});
},
let item = {
...items[1],
name: 'newName'
}
this.setState(({items}) => ({
items: [
...items.slice(0,1),
{
...items[1],
name: 'newName',
},
...items.slice(2)
]
}));
❯ 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
handleChange: function (e) {
items = Object.assign(this.state.items); // Pull the entire items object out. Using object.assign is a good idea for objects.
items[1].name = 'newName'; // update the items object as needed
this.setState({ items }); // Put back in state
}
this.setState(prevState => {
const newItems = [...prevState.items];
newItems[index].name = newName;
return {items: newItems};
})
this.setState({items: this.state.items.map((item,idx)=> idx!==1 ?item :{...item,name:'new_name'}) })
let ItemsCopy = []
let x = this.state.Items.map((entry) =>{
if(entry.id == 'theIDYoureLookingFor')
{
entry.PropertyToChange = 'NewProperty'
}
ItemsCopy.push(entry)
})
this.setState({Items:ItemsCopy});
this.state.items[1] = 'new value';
var cloneObj = Object.assign({}, this.state.items);
this.setState({items: cloneObj });
var udpateditem = this.state.items.find(function(item) {
return item.name == "field_1" });
udpateditem.name= "New updated name"
this.setState(prevState => ({
items:prevState.dl_name_template.filter(function(item) {
return item.name !== "field_1"}).concat(udpateditem)
}));
handleChanges = (value, key) => {
// clone the current State object
let cloneObject = _.extend({}, this.state.currentAttribute);
// key as user.name and value= "ABC" then current attributes have current properties as we changes
currentAttribute[key] = value;
// then set the state "currentAttribute" is key and "cloneObject" is changed object.
this.setState({currentAttribute: cloneObject});
onChange = {
(event) => {
this.handleChanges(event.target.value, "title");
}
}
constructor(props) {
super(props)
this.state = { values: [] }
this.updateContainerState = this.updateContainerState.bind(this)
}
updateContainerState(index, value) {
this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
}
import React from 'react'
import update from 'immutability-helper'
import { ContainerElement } from './container.component.style.js'
import ChildComponent from './child-component'
export default class ContainerComponent extends React.Component {
constructor(props) {
super(props)
this.state = { values: [] }
this.updateContainerState = this.updateContainerState.bind(this)
}
updateContainerState(index, value) {
this.setState((state) => update(state, { values: { [index]: { $set: value } } }))
}
// ...
render() {
let index = 0
return (
<ContainerElement>
<ChildComponent
index={index++}
containerState={this.state}
updateContainerState={this.updateContainerState}
/>
<ChildComponent
index={index++}
containerState={this.state}
updateContainerState={this.updateContainerState}
/>
</ContainerElement>
)
}
}
this.setState({
items: this.state.items.map((item,index) => {
if (index === 1) {
item.name = 'newName';
}
return item;
})
});
this.setState({
items: this.state.items.map((item, index) =>
index === 1 ? { ...item, name: 'newName' } : item,
)
})
inputChange = input => e => {
this.setState({
item: update(this.state.item, {[input]: {$set: e.target.value}})
})
}
const myNewArray = Object.assign([...myArray], {
[index]: myNewItem
});
setState({ myArray: myNewArray });
const myNewArray = Object.assign([...myArray], {
[index]: {
...myArray[index],
prop: myNewValue
}
});
setState({ myArray: myNewArray });