Ale*_*ong 288 javascript setstate ecmascript-6 reactjs
我试图通过使用这样的嵌套属性来组织我的状态:
this.state = {
someProperty: {
flag:true
}
}
Run Code Online (Sandbox Code Playgroud)
但是像这样更新状态,
this.setState({ someProperty.flag: false });
Run Code Online (Sandbox Code Playgroud)
不起作用.怎么能正确完成?
Shu*_*tri 352
为了setState
嵌套对象,您可以遵循以下方法,因为我认为setState不处理嵌套更新.
var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})
Run Code Online (Sandbox Code Playgroud)
我们的想法是创建一个虚拟对象对其执行操作,然后用更新的对象替换组件的状态
现在,spread运算符只创建对象的一个级别嵌套副本.如果您的州高度嵌套,如:
this.state = {
someProperty: {
someOtherProperty: {
anotherProperty: {
flag: true
}
..
}
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
您可以在每个级别使用spread运算符setState
this.setState(prevState => ({
...prevState,
someProperty: {
...prevState.someProperty,
someOtherProperty: {
...prevState.someProperty.someOtherProperty,
anotherProperty: {
...prevState.someProperty.someOtherProperty.anotherProperty,
flag: false
}
}
}
}))
Run Code Online (Sandbox Code Playgroud)
但是,随着状态变得越来越嵌套,上面的语法变得越来越难看,因此我建议你使用immutability-helper
package来更新状态.
请参阅此答案,了解如何使用更新状态immutability helper
.
Yos*_*eph 120
把它写在一行
this.setState({ someProperty: { ...this.state.someProperty, flag: false} });
Run Code Online (Sandbox Code Playgroud)
Kon*_*nin 70
有时直接答案不是最好的:)
精简版:
这段代码
this.state = {
someProperty: {
flag: true
}
}
Run Code Online (Sandbox Code Playgroud)
应简化为类似的东西
this.state = {
somePropertyFlag: true
}
Run Code Online (Sandbox Code Playgroud)
长版:
目前,您不应该在React中使用嵌套状态.因为React不适用于嵌套状态,所以这里提出的所有解决方案都看起来像黑客.他们不使用框架,而是与之斗争.他们建议编写不那么清晰的代码,以便对某些属性进行分组.所以他们作为挑战的答案非常有趣但实际上没用.
让我们想象以下状态:
{
parent: {
child1: 'value 1',
child2: 'value 2',
...
child100: 'value 100'
}
}
Run Code Online (Sandbox Code Playgroud)
如果你只改变一个值会发生什么child1
?React不会重新渲染视图,因为它使用浅层比较,它会发现该parent
属性没有改变.BTW直接改变状态对象被认为是一种不好的做法.
所以你需要重新创建整个parent
对象.但在这种情况下,我们将遇到另一个问题.React会认为所有的孩子都改变了他们的价值观,并且会重新渲染他们所有的孩子.当然这对性能不利.
通过编写一些复杂的逻辑仍然可以解决这个问题,shouldComponentUpdate()
但我宁愿停在这里并使用简短版本的简单解决方案.
Qwe*_*rty 51
React中的嵌套状态是错误的设计
阅读这个优秀的答案.
这个答案背后的推理:
React的setState只是一个内置的便利,但你很快意识到它有其局限性.使用自定义属性和智能使用forceUpdate可以提供更多功能.例如:
Run Code Online (Sandbox Code Playgroud)class MyClass extends React.Component { myState = someObject inputValue = 42 ...
例如,MobX完全抛弃状态并使用自定义可观察属性.
在React组件中使用Observable而不是state.
还有另一种更新嵌套属性的更短方法.
this.setState(state => {
state.nested.flag = false
state.another.deep.prop = true
return state
})
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)this.setState(state => (state.nested.flag = false, state))
当然这是滥用一些核心原则,因为它forceUpdate
应该是只读的,但由于你立即丢弃旧状态并用新状态替换它,这是完全没问题的.
即使包含状态的组件将正确更新和重新呈现(除了这个问题),道具将无法传播给孩子(请参阅下面的Spymaster评论).如果你知道自己在做什么,只能使用这种技术.
例如,您可以传递更改并轻松传递的更改的平面道具.
this.state.nested.flag = false
this.forceUpdate()
Run Code Online (Sandbox Code Playgroud)
现在即使complexNestedProp的引用没有改变(shouldComponentUpdate)
render(
//some complex render with your nested state
<ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)
Run Code Online (Sandbox Code Playgroud)
只要父组件更新,组件就会重新出现,这是在调用之后setState
或state
在父组件中更新的情况.
Aly*_*ose 21
如果您使用的是ES2015,则可以访问Object.assign.您可以按如下方式使用它来更新嵌套对象.
this.setState({
someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});
Run Code Online (Sandbox Code Playgroud)
您将更新的属性与现有属性合并,并使用返回的对象更新状态.
编辑:向assign函数添加一个空对象作为目标,以确保状态不会像carkod指出的那样直接变异.
tok*_*and 13
有很多图书馆可以帮助解决这个问题.例如,使用immutability-helper:
import update from 'immutability-helper';
const newState = update(this.state, {
someProperty: {flag: {$set: false}},
};
this.setState(newState);
Run Code Online (Sandbox Code Playgroud)
或者使用lodash/fp:
import {set} from 'lodash/fp';
const newState = set(["someProperty", "flag"], false, this.state);
Run Code Online (Sandbox Code Playgroud)
enz*_*ito 12
你也可以这样(这对我来说更具可读性):
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);
Run Code Online (Sandbox Code Playgroud)
小智 6
这是该线程中给出的第一个答案的变体,它不需要任何额外的包,库或特殊功能.
state = {
someProperty: {
flag: 'string'
}
}
handleChange = (value) => {
const newState = {...this.state.someProperty, flag: value}
this.setState({ someProperty: newState })
}
Run Code Online (Sandbox Code Playgroud)
为了设置特定嵌套字段的状态,您已设置整个对象.我这样做是通过创建一个变量,newState
然后首先使用ES2015 扩展运算符将当前状态的内容传播到其中.然后,我用this.state.flag
新值替换了值(因为我flag: value
在将当前状态扩展到对象后设置,所以当前状态中的flag
字段被覆盖).然后,我只是将状态设置someProperty
为我的newState
对象.
我们使用Immer https://github.com/mweststrate/immer来处理这些问题.
刚刚在我们的一个组件中替换了这段代码
this.setState(prevState => ({
...prevState,
preferences: {
...prevState.preferences,
[key]: newValue
}
}));
Run Code Online (Sandbox Code Playgroud)
有了这个
import produce from 'immer';
this.setState(produce(draft => {
draft.preferences[key] = newValue;
}));
Run Code Online (Sandbox Code Playgroud)
使用immer,您可以将状态视为"普通对象".魔术发生在具有代理对象的场景后面.
虽然你问的是基于类的 React 组件的状态,但 useState hook 也存在同样的问题。更糟糕的是:useState 钩子不接受部分更新。因此,当引入 useState 钩子时,这个问题变得非常相关。
我决定发布以下答案,以确保问题涵盖使用 useState 钩子的更现代场景:
如果你有:
const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })
Run Code Online (Sandbox Code Playgroud)
您可以通过克隆当前数据并修补所需的数据段来设置嵌套属性,例如:
setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });
Run Code Online (Sandbox Code Playgroud)
或者您可以使用 Immer 库来简化对象的克隆和修补。
或者你可以使用Hookstate 库(免责声明:我是作者)来完全简单地管理复杂(本地和全局)状态数据并提高性能(阅读:不用担心渲染优化):
import { useStateLink } from '@hookstate/core'
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })
Run Code Online (Sandbox Code Playgroud)
获取要渲染的字段:
state.nested.someProperty.nested.flag.get()
// or
state.get().someProperty.flag
Run Code Online (Sandbox Code Playgroud)
设置嵌套字段:
state.nested.someProperty.nested.flag.set(false)
Run Code Online (Sandbox Code Playgroud)
这是 Hookstate 示例,其中状态深度/递归嵌套在树状数据结构中。
我使用了这个解决方案。
如果您有这样的嵌套状态:
this.state = {
formInputs:{
friendName:{
value:'',
isValid:false,
errorMsg:''
},
friendEmail:{
value:'',
isValid:false,
errorMsg:''
}
}
Run Code Online (Sandbox Code Playgroud)
您可以声明 handleChange 函数来复制当前状态并使用更改的值重新分配它
handleChange(el) {
let inputName = el.target.name;
let inputValue = el.target.value;
let statusCopy = Object.assign({}, this.state);
statusCopy.formInputs[inputName].value = inputValue;
this.setState(statusCopy);
}
Run Code Online (Sandbox Code Playgroud)
这里是带有事件侦听器的 html
<input type="text" onChange={this.handleChange} " name="friendName" />
Run Code Online (Sandbox Code Playgroud)
小智 5
创建状态的副本:
let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))
Run Code Online (Sandbox Code Playgroud)
对此对象进行更改:
someProperty.flag = "false"
Run Code Online (Sandbox Code Playgroud)
现在更新状态
this.setState({someProperty})
Run Code Online (Sandbox Code Playgroud)
小智 5
尽管嵌套并不是您应该如何对待组件状态的真正方法,但有时对于单层嵌套来说还是容易的。
对于这样的状态
state = {
contact: {
phone: '888-888-8888',
email: 'test@test.com'
}
address: {
street:''
},
occupation: {
}
}
Run Code Online (Sandbox Code Playgroud)
我所使用的可重用方法如下所示。
handleChange = (obj) => e => {
let x = this.state[obj];
x[e.target.name] = e.target.value;
this.setState({ [obj]: x });
};
Run Code Online (Sandbox Code Playgroud)
然后只需为您要寻址的每个嵌套传递obj名称...
<TextField
name="street"
onChange={handleChange('address')}
/>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
180295 次 |
最近记录: |