【发布时间】:2016-01-18 00:43:42
【问题描述】:
我正在尝试清除组件state,但找不到 es6 语法的参考。我正在使用:
this.replaceState(this.getInitialState());
但是这不适用于 es6 类语法。
我怎样才能达到同样的效果?
【问题讨论】:
标签: javascript reactjs
我正在尝试清除组件state,但找不到 es6 语法的参考。我正在使用:
this.replaceState(this.getInitialState());
但是这不适用于 es6 类语法。
我怎样才能达到同样的效果?
【问题讨论】:
标签: javascript reactjs
据我所知,React 组件不会保留初始状态的副本,因此您只需要自己完成即可。
const initialState = {
/* etc */
};
class MyComponent extends Component {
constructor(props) {
super(props)
this.state = initialState;
}
reset() {
this.setState(initialState);
}
/* etc */
}
请注意,this.state = initialState; 行要求你永远不要改变你的状态,否则你会污染initialState 并使重置变得不可能。如果无法避免突变,则需要在构造函数中创建initialState 的副本。 (或者按照getInitialState() 将initialState 设为一个函数。)
最后,我建议你使用setState() 而不是replaceState()。
【讨论】:
replaceState 在这种情况下非常好,因为它确保状态对象的 entirety 返回到一组已知的值。
replaceState() 甚至都不可用。自从我发布此答案以来,我才意识到这一点。
setState 合并状态。如果组件向状态中添加了不在initialState 中的字段,这些字段将不会被清除。
state,那么它也会更改initialState,因为它是通过引用分配的。因此,当您调用重置时,它实际上不会重置为initialState。没有任何变化,您必须将initialState 深复制到state
接受的答案:
const initialState = {
/* etc */
};
class MyComponent extends Component {
constructor(props) {
super(props)
this.state = initialState;
}
reset() {
this.setState(initialState);
}
/* etc */
}
不幸的是不正确。
initialState 被作为对this.state 的引用传递,因此无论何时更改state,您也更改了initialState(const 在这里并不重要)。结果是你永远无法回到initialState。
你必须深拷贝 initialState 到 state,然后它会起作用。要么自己写一个深拷贝函数,要么使用一些现有的模块,比如this。
【讨论】:
Object.assign({}, nextState, partialState);。所以,没必要做initialState的深拷贝,因为this.state总是setState之后的一个新对象。好的,Object.assign 只克隆一个级别......但是使用 setState 方法保存的所有状态都应该没有改变状态,传递一个带有更改的新副本。
initialState 对象引用是完全可以的。
这是作为函数实现的解决方案:
Class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = this.getInitialState();
}
getInitialState = () => ({
/* state props */
})
resetState = () => {
this.setState(this.getInitialState());
}
}
【讨论】:
涉及直接设置 this.state 的解决方案在 React 16 中对我不起作用,所以这是我重置每个键的方法:
const initialState = { example: 'example' }
...
constructor() {
super()
this.state = initialState
}
...
reset() {
const keys = Object.keys(this.state)
const stateReset = keys.reduce((acc, v) => ({ ...acc, [v]: undefined }), {})
this.setState({ ...stateReset, ...initialState })
}
【讨论】:
首先,您需要在组件生命周期中使用 componentWillMount() 函数时存储初始状态:
componentWillMount() {
this.initialState = this.state
}
这会存储您的初始状态,并且可以在您需要时通过调用来重置状态
this.setState(this.initialState)
【讨论】:
const initialState = {
a: '',
b: '',
c: ''
};
class ExampleComponent extends Component {
state = { ...initialState } // use spread operator to avoid mutation
handleReset = this.handleReset.bind(this);
handleReset() {
this.setState(initialState);
}
}
请记住,为了能够重置状态,重要的是不要改变 initialState。
state = {...initialState} // GOOD
// => state points to a new obj in memory which has the values of initialState
state = initialState // BAD
// => they point to the same obj in memory
最方便的方法是使用 ES6 扩展运算符。但是你也可以使用 Object.assign 来代替。他们都会达到同样的效果。
state = Object.assign({}, initialState); // GOOD
state = {...initialState}; // GOOD
【讨论】:
在大多数情况下,您不需要深拷贝,很少有初始状态是对象的对象,因此使用 babel 转换为 object.assign 的扩展运算符应该没问题。
所以,在构造函数内部你会:
class MyComponent extends Component {
constructor(props) {
super(props)
this.state = {
key: value,
key2: value
}
this.initialState = { ...this.state }
}
}
从那里你可以使用
this.setState(this.initialState);
重置。但是如果由于某种原因您的初始状态是更复杂的对象,请使用一些库。
【讨论】:
我是这样处理的:
class MyComponent extends React.Component{
constructor(props){
super(props);
this._initState = {
a: 1,
b: 2
}
this.state = this._initState;
}
_resetState(){
this.setState(this._initState);
}
}
更新: 其实这是错误的。对于未来的读者,请参阅@RaptoX 答案。 此外,您可以使用不可变库来防止由引用分配引起的奇怪的状态修改。
【讨论】:
this._initState 不会在您的构造函数中未定义吗?你的意思是this.state = this._initialState?
我将在上面的答案中添加重置功能也应该像这样分配状态:
reset() {
this.state = initialState;
this.setState(initialState);
}
原因是,如果您的状态选择了一个不在初始状态的属性,则该键/值不会被清除,因为 setState 只是更新现有键。赋值不足以让组件重新渲染,所以还要包含 setState 调用——你甚至可以在赋值后使用 this.setState({})。
【讨论】:
this.state = initialState;
在某些情况下,只需将state 的所有值都设置为null。
如果你的状态以这样的方式更新,你不知道那里可能有什么,你可能想要使用
this.setState(Object.assign(...Object.keys(this.state).map(k => ({[k]: null}))))
这将改变状态如下
{foo: 1, bar: 2, spam: "whatever"} > {foo: null, bar: null, spam: null}
并非在所有情况下都是解决方案,但对我来说效果很好。
【讨论】:
您可以克隆您的状态对象,遍历每个状态对象,并将其设置为undefined。不过,这种方法不如公认的答案好。
const clonedState = this.state;
const keys = Object.keys(clonedState);
keys.forEach(key => (clonedState[key] = undefined));
this.setState(clonedState);
【讨论】:
class MyComponent extends Component {
constructor(props){
super(props)
this.state = {
inputVal: props.inputValue
}
// preserve the initial state in a new object
this.baseState = this.state
}
resetForm = () => {
this.setState(this.baseState)
}
}
【讨论】:
使用深拷贝,你可以用 lodash 做到这一点:
import _ from "lodash";
const INITIAL_STATE = {};
constructor(props) {
super(props);
this.state = _.cloneDeep(INITIAL_STATE);
}
reset() {
this.setState(_.cloneDeep(INITIAL_STATE));
}
【讨论】:
class x extends Components {
constructor() {
super();
this.state = {
name: 'mark',
age: 32,
isAdmin: true,
hits: 0,
// since this.state is an object
// simply add a method..
resetSelectively() {
//i don't want to reset both name and age
// THIS IS FOR TRANSPARENCY. You don't need to code for name and age
// it will assume the values in default..
// this.name = this.name; //which means the current state.
// this.age = this.age;
// do reset isAdmin and hits(suppose this.state.hits is 100 now)
isAdmin = false;
hits = 0;
}// resetSelectively..
}//constructor..
/* now from any function i can just call */
myfunction() {
/**
* this function code..
*/
resetValues();
}// myfunction..
resetValues() {
this.state.resetSelectively();
}//resetValues
/////
//finally you can reset the values in constructor selectively at any point
...rest of the class..
}//class
【讨论】: