简体   繁体   English

如何正确更新对象的状态(ReactJS + Redux)?

[英]How to properly update state of an object (ReactJS + Redux)?

So I have two input fields: 所以我有两个输入字段:

  <TextField onChange={this.handleUserUsername.bind(this)}
    value={this.props.userInfo.username}
  />

  <TextField onChange={this.handleUserEmail.bind(this)}
    value={this.props.userInfo.email}
  />

once entered, I would like to store them in the state of an object named 'userInfo', like so: 一旦输入,我想将它们存储在名为'userInfo'的对象的状态中,如下所示:

  handleUserUsername(event){
    this.props.actions.updateUsername(event.target.value)
  }

  handleUserEmail(event){
    this.props.actions.updateEmail(event.target.value)
  } 

and the action creators are: 并且动作创建者是:

  updateUsername: function(eventValue){
    return {
      type: 'UPDATE_USERNAME',
      username: eventValue
    }
  },

  updateEmail: function(eventValue){
    return {
      type: 'UPDATE_USERNAME',
      email: eventValue
    }
  }

and the reducer is: 减速机是:

function(userInfo={}, action){
  switch(action.type){
    case 'UPDATE_USERNAME':
      return {
        username: action.username
      }

    case 'UPDATE_EMAIL':
      return {
        email: action.email
      }

But once texts are inputted into username TextField, it displays whatever it is typed in the TextField and correctly stores 'Z' for the 'username' and logs the following (in the example, 'Z' was typed in): 但是一旦将文本输入到用户名TextField中,它就会显示在TextField中键入的内容,并正确存储“用户名”的“Z”并记录以下内容(在示例中,输入“Z”):

在此输入图像描述

Then when a text, 'M' in this example, is entered into the email TextField, the username state becomes 'undefined' when it should stay as Z, and email state is not even stored: 然后,当本例中的文本“M”输入到电子邮件TextField中时,用户名状态变为“未定义”时,它应保持为Z,并且甚至不存储电子邮件状态:

在此输入图像描述

In the log for the example, what I am hoping to see is: 在示例的日志中,我希望看到的是:

userInfo: Object
    username: "Z"
    email: "M"

And I am using the following to access state and actions: 我正在使用以下内容来访问状态和操作:

function mapStateToProps(state) {
  return state
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(actions, dispatch)
  }
}

Why isn't it correctly storing the state for the 'userInfo' object? 为什么不正确存储'userInfo'对象的状态? What would be the proper way to update such an object? 更新这样一个对象的正确方法是什么? Eventually I want to store the 'userInfo' object into an array called users, where it would store all the user information. 最终我想将'userInfo'对象存储到一个名为users的数组中,它将存储所有用户信息。

EDIT ** 编辑**

When I entered 'q' in the username textfield, the following shows: 当我在用户名文本字段中输入“q”时,显示如下:

在此输入图像描述

Then when I enter 'm' in the password textfield, both become undefined now: 然后当我在密码文本字段中输入“m”时,两者现在都变为未定义:

在此输入图像描述

EDIT 2 ** 编辑2 **

const registerReducer = function(userInfo={}, action){
  switch(action.type){
    case 'UPDATE_USERNAME':
      return {
        ...userInfo,
        username: action.username
      }

    case 'UPDATE_EMAIL':
      return {
        ...userInfo,
        email: action.email
      }

In your example you missed that you should be returning the existing state along with the changes that happened as result of your action, altering the previous state. 在您的示例中,您错过了应该返回现有状态以及由于操作而发生的更改,从而更改以前的状态。

This is what a reducer does: 这就是减速机的作用:

Actions describe the fact that something happened, but don't specify how the application's state changes in response. 操作描述了事情发生的事实,但没有指定应用程序的状态如何响应变化。 This is the job of a reducer. 这是减速机的工作。

What you need to do is to always return a new state object that is the result of applying your reducer to the old state object for the particular action that happened. 您需要做的是始终返回一个新的状态对象,该状态对象是将reducer应用于发生的特定操作的旧状态对象的结果。

Instead of 代替

case 'SOME_ACTION_TYPE':
  return {
    someProperty: 'theNewValue'
  }

What you should do is: 你应该做的是:

case 'SOME_ACTION_TYPE':
  return {
    ...state, // notice how I create a new object, but preserve all of the old
    propertyThatIChangedInMyReducer: 'theNewValue' // this will override the old
  }

Basically, you take the reducer, apply the changes that you would for the specific action that happened and return that new object, that also contains the other part of the state tree that remained unchanged. 基本上,您使用reducer,应用您对发生的特定操作所做的更改并返回该新对象,该对象还包含状态树的其他部分,该部分保持不变。 You missed returning the other part. 你错过了返回另一部分。

If let's say you had a password field too that you would treat in a similar manner, you would do something like this: 如果让我们说你有一个密码字段,你会以类似的方式对待,你会做这样的事情:

case 'UPDATE_PASSWORD':
  return {
    ...state, //preserve current state, apply changes to it below
    password: action.password,
  }; 

I think the problem is that you create updated state object that contains information only about changed fields. 我认为问题是您创建的更新状态对象包含仅有关已更改字段的信息。 Due to one of the Redux's principles its state should be immutable and each time you want to update it you should create new state object with needed changes. 由于Redux的一个原则,它的状态应该是不可变的,每次你想要更新它时,你应该创建具有所需更改的新状态对象。

In your case, you should return both fields when creating new state object (even if one of them didn't change): 在您的情况下,您应该在创建新状态对象时返回两个字段(即使其中一个没有更改):

function(userInfo={}, action){
  switch(action.type){
  case 'UPDATE_USERNAME':
    return {
      username: action.username,
      email: userInfo.email     // userInfo is current state, we should save old value
    }

  case 'UPDATE_EMAIL':
    return {
      username: userInfo.username,  // userInfo is current state, we should save old value
      email: action.email      
    }

By this you create new state which contains fields that didn't changed(with same values) and fields that changed(with new values) 通过此操作,您可以创建新状态,其中包含未更改的字段(具有相同的值)和更改的字段(使用新值)

EDIT : 编辑:

more examples: 更多例子:

assume that state of your application is the following: 假设您的应用程序状态如下:

oldState = {
    email: "oldValue",
    userName: "oldValue"
}

Then if you trying to change email, you reducer should return state object in the following way: 然后,如果您尝试更改电子邮件,则reducer应按以下方式返回状态对象:

return Object.assign({}, oldState, {
    email: "newValue"
})

Code above will produce new state object basing on the old state and change email attribute in the new one. 上面的代码将根据旧状态生成新的状态对象,并在新的状态中更改电子邮件属性。 Object.assign Object.assign

As a result your new state will look like this: 因此,您的新州将如下所示:

{
    email: "newValue",
    userName: "oldValue"    
}

In your example your reducer return state object like this: 在您的示例中,reducer返回状态对象,如下所示:

{
    email: "newValue",
}

So the redux cannot understand what current value for userName is. 因此redux无法理解userName的当前值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM