【问题标题】:Clearing state es6 React清除状态 es6 React
【发布时间】:2016-01-18 00:43:42
【问题描述】:

我正在尝试清除组件state,但找不到 es6 语法的参考。我正在使用:

this.replaceState(this.getInitialState());

但是这不适用于 es6 类语法。

我怎样才能达到同样的效果?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    据我所知,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 返回到一组已知的值。
    • 实际上,在使用 ES6 类时,replaceState() 甚至都不可用。自从我发布此答案以来,我才意识到这一点。
    • 请注意setState 合并状态。如果组件向状态中添加了不在initialState 中的字段,这些字段将不会被清除。
    • 如果您将字段添加到未在初始状态中定义的状态,那么您做错了。
    • 这不能正常工作,因为如果您更改state,那么它也会更改initialState,因为它是通过引用分配的。因此,当您调用重置时,它实际上不会重置为initialState。没有任何变化,您必须将initialState 深复制到state
    【解决方案2】:

    问题

    接受的答案

    const initialState = {
        /* etc */
    };
    
    class MyComponent extends Component {
        constructor(props) {
            super(props)
            this.state = initialState;
        }
        reset() {
            this.setState(initialState);
        }
        /* etc */
    }
    

    不幸的是不正确

    initialState 被作为对this.state 的引用传递,因此无论何时更改state,您也更改了initialStateconst 在这里并不重要)。结果是你永远无法回到initialState

    解决方案

    你必须深拷贝 initialStatestate,然后它会起作用。要么自己写一个深拷贝函数,要么使用一些现有的模块,比如this

    【讨论】:

    • 你是对的。这也是 Immutable.js(和其他不可变库)存在的原因。
    • 在后台,React 正在执行Object.assign({}, nextState, partialState);。所以,没必要做initialState的深拷贝,因为this.state总是setState之后的一个新对象。好的,Object.assign 只克隆一个级别......但是使用 setState 方法保存的所有状态都应该没有改变状态,传递一个带有更改的新副本。
    • 如果这个答案是正确的,当我将状态设置为初始状态然后尝试再次重置时,我会遇到问题。但这根本没有发生。对此答案投票的用户并不真正了解发生了什么。我现在很沮丧,很多人都被这种可疑的理解所欺骗,尤其是因为它很容易测试。
    • 我有疑问?为什么我们不能在构造函数中初始化一个空状态,然后在 componentDidMount 中更新我们的 initialState?使用生命周期方法会导致任何问题吗?如果这可行,那么我们稍后可以轻松更新 initialState。
    • 除非您自己改变状态(也就是代码异味),否则使用相同的 initialState 对象引用是完全可以的。
    【解决方案3】:

    这是作为函数实现的解决方案:

    Class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = this.getInitialState();
      }
    
      getInitialState = () => ({
        /* state props */
      })
    
      resetState = () => {
         this.setState(this.getInitialState());
      }
    }
    

    【讨论】:

    • 有了这个选项,我就不需要做深拷贝了。
    【解决方案4】:

    涉及直接设置 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 })
      }
    

    【讨论】:

    • 类选择状态的变体 const keys = Object.keys(this.state); const stateReset = keys.reduce((acc, v) => ({ ...acc, [v]: false }), {}); this.setState(stateReset);
    • 与上面投票率较高的答案不同,此解决方案实际上清除了任何不再在初始状态中声明的状态元素。赞一个!
    • 是的,这是一个很好的答案,如果你不这样做,初始化后设置的其他状态仍然存在。
    【解决方案5】:

    首先,您需要在组件生命周期中使用 componentWillMount() 函数时存储初始状态:

    componentWillMount() {
        this.initialState = this.state
    }
    

    这会存储您的初始状态,并且可以在您需要时通过调用来重置状态

    this.setState(this.initialState)
    

    【讨论】:

      【解决方案6】:
      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
      

      【讨论】:

        【解决方案7】:

        在大多数情况下,您不需要深拷贝,很少有初始状态是对象的对象,因此使用 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);
        

        重置。但是如果由于某种原因您的初始状态是更复杂的对象,请使用一些库。

        【讨论】:

          【解决方案8】:

          我是这样处理的:

          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
          【解决方案9】:

          我将在上面的答案中添加重置功能也应该像这样分配状态:

          reset() {
            this.state = initialState;
            this.setState(initialState);
          }
          

          原因是,如果您的状态选择了一个不在初始状态的属性,则该键/值不会被清除,因为 setState 只是更新现有键。赋值不足以让组件重新渲染,所以还要包含 setState 调用——你甚至可以在赋值后使用 this.setState({})。

          【讨论】:

          • 这似乎有点矫枉过正。这真的是人们应该这样做的方式吗?
          • 你在 React 生命周期之外改变状态......这是不正确的 React。
          • 你不应该这样做this.state = initialState;
          【解决方案10】:

          在某些情况下,只需将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}
          

          并非在所有情况下都是解决方案,但对我来说效果很好。

          【讨论】:

            【解决方案11】:

            您可以克隆您的状态对象,遍历每个状态对象,并将其设置为undefined。不过,这种方法不如公认的答案好。

            const clonedState = this.state;
            
            const keys = Object.keys(clonedState);
            keys.forEach(key => (clonedState[key] = undefined));
            
            this.setState(clonedState);
            

            【讨论】:

            • 在回答一个老问题时,如果您包含一些上下文来解释您的答案如何提供帮助,那么您的答案将对其他 StackOverflow 用户更有用,特别是对于已经有一个已接受答案的问题。请参阅:How do I write a good answer
            【解决方案12】:
            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)
              }
            
            }
            

            【讨论】:

              【解决方案13】:

              使用深拷贝,你可以用 lodash 做到这一点:

              import _ from "lodash";
              
              const INITIAL_STATE = {};
              
              constructor(props) {
                  super(props);
                  this.state = _.cloneDeep(INITIAL_STATE);
              }
              
              reset() {
                  this.setState(_.cloneDeep(INITIAL_STATE));
              }
              

              【讨论】:

                【解决方案14】:
                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
                

                【讨论】:

                  猜你喜欢
                  • 2016-05-29
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-07-22
                  • 2019-05-05
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多