【问题标题】:Redux previous state already has new state valueRedux 之前的 state 已经有了新的 state 值
【发布时间】:2017-01-29 14:10:00
【问题描述】:

我正在尝试使用 React 和 Redux 来处理受控表单,并且我已经让它工作了,因此当我在输入字段中输入时,状态正在更新并按预期传递到输入组件.

但是,在我的 reducer 中,当我在控制台记录之前的状态时,表单字段的值不包含输入新字符之前的值,它已经有了新字符。

我的减速机:

import initialState from '../state/form'
const form = (prevState = initialState, action) => {

  switch (action.type) {

    case 'INPUT': {
      console.log(prevState) // the value here equals "test"
      debugger // the value here equals "tes"
      let newFields = prevState.fields
      newFields[action.field].value = action.value
      return Object.assign({}, prevState, {
        fields: newFields
      })
    }

    default: {
      return prevState
    }
  }
}

export default form

如果我的输入字段包含文本“tes”,然后我可以添加一个“t”并且按预期调度操作,但是当它到达这个减速器时,我控制台记录以前的状态并且该字段的值是“测试”,而不是“测试”。

我希望之前的状态有“tes”,reducer 用“test”返回新的状态。

在我的容器中,我有:

const dispatchToProps = (dispatch, ownProps) => {
  return {
    control: (e) => {
      dispatch({
        type: 'INPUT',
        form: ownProps.formId,
        field: e.target.getAttribute('name'),
        value: e.target.value
      })
    },
    clear: () => {
      dispatch({
        type: 'CLEAR_FORM',
        form: ownProps.formId
      })
    }
  }
}

所以我的输入组件正在传递“控制”功能。从那以后,我在上面的 reducer 代码中的 console.log 旁边使用了一个调试器语句,并使用 Chrome 的开发工具,这显示 prevState 完全符合我的预期(测试,而不是测试)。但是,console.log 仍在记录“测试”!

所以看来我的 redux 实现可能没问题,在 console.log(prevState) == "test" 的某个地方只有一些巫术,调试器允许我观察 prevState 变量并显示它等于 "tes",如期待!

感谢您的回答@Pineda。在查看奇怪的控制台日志行为时(当您输入答案时)我遇到了 variables are references to objects 事实 (here) - 我已经停止改变我的状态,并更新了我的减速器:

import initialState from '../state/form'
const form = (state = initialState, action) => {
  switch (action.type) {

    case 'INPUT': {
      return Object.assign({}, state, {
        fields: {
          ...state.fields,
          [action.field]: {
            ...state.fields[action.field],
            value: action.value
          }
        }
      })
    }

    default: {
      return state
    }
  }
}

现在一切正常。由于我的 mapStateToProps 方法中的错误,我可能似乎已经摆脱了变异状态,必须解决这个问题才能使新的减速器正常工作。

【问题讨论】:

  • 进一步检查,当我在 Chrome 中使用调试器时,之前的状态会按预期显示,所以我猜这可能是控制台日志问题

标签: javascript reactjs redux


【解决方案1】:

你正在改变状态在这些行中:

  let newFields = prevState.fields
  newFields[action.field].value = action.value
  // it's also worth noting that you're trying to access a 'value'
  // property on newFields[action.field], which doesn't look
  // like it'll exist

可以改写为:

  prevState.fields[action.field] = action value

然后你使用你的变异状态来创建一个新对象。

解决办法:

import initialState from '../state/form'
const form = (prevState = initialState, action) => {

  switch (action.type) {

    case 'INPUT': {
      console.log(prevState);
      // You create a new un-mutated state here
      // With a property 'fields' which is an object
      // with property name whose value is action.field
      // which has the value action.value assigned to it
      const newState = Object.assign({}, prevState, {
        fields: { [action.field]: action.value}
      });
      return 
    }

    default: {
      return prevState
    }
  }
}

export default form

【讨论】:

    【解决方案2】:

    我猜你正在将输入直接绑定到你的 redux 商店属性:

    <input
      value={this.props.name}
      onChange={e => this.props.name = e.target.value}
    />
    

    请记住,值是通过引用而不是通过值传递的,如果您直接修改存储值,那么当动作触发时,您将已经改变了您的 redux 存储状态(这是一个很大的禁忌)

    我的建议是,试着找出你是如何在你的代码库中传递这个状态的,你应该有类似的东西:

    <input
      value={this.props.name}
      onChange={e => dispatch({type: 'INPUT', field: 'name', value: e.target.value })}
    />
    

    【讨论】:

    • 我在输入标签上将一个函数传递给我的 onChange 处理程序,该函数通过 mapDispatchToProps 向下传递,实际上正如您的第二个示例所示。从那以后,我使用了 Chrome 调试器(使用 console.log 行上方的调试器语句),它按预期显示了以前的状态,这与 console.log 不同。似乎一切正常,除了 console.log!
    • 您介意用代码更新您的问题吗?
    猜你喜欢
    • 2016-01-29
    • 2018-01-07
    • 1970-01-01
    • 2021-09-21
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    相关资源
    最近更新 更多