首页 > 解决方案 > 在 mapStateToProps 中使用扩展运算符 (...) 会导致将过时的值传递给子组件

问题描述

我的组件有这样的代码,它是一个功能组件:

useEffect(() => {
  if (errors['update'].error || successes['update'].success) {
    setUpdateInProgress(false);
  }
}, [errors['update'].error, successes['update'].success])

errorsuccess属性相互独立,当其中任何一个为真时,我想调用setUpdateInProgress.

mapStateToProps我有这样的代码:

const mapStateToProps = (store) => {
  return {
      // other fields
      errors: {...store.prop1.errors, ...store.prop2.errors},
      successes: {...store.prop1.errors, ...store.prop2.errors};
}

这些errorssuccesses对象是我需要发送到我的组件以useEffect使其工作的道具。很明显,我想将多个地方的属性组合成一个(prop1,,prop2...)。

问题是,它不起作用,并且useEffect没有调用。为了让它工作,我必须像下面这样拆分道具:

const mapStateToProps = (store) => {
  return {
      // other fields
      prop1Errors: store.prop1.errors,
      prop2Errors: store.prop2.errors,
      prop1Successes: store.prop1.successes,
      prop2Successes: store.prop2.successes
  }

为什么扩展运算符会导致从状态设置陈旧值,而直接使用状态值不会?

编辑:对于那些感兴趣的人,errors并且successes有这样的结构:

errors: {
  create: {
    error: true,
    message: "Error in create"
  },
  update: {
    error: false,
    message: ""
  }
  //... same thing for other actions like fetch, etc
}

//... same thing for successes

至于reducer代码,是这样的:

function reducer(state, action) {
  if(action === "UPDATE") {
    return {...state, errors: { ...state.errors, update: { message: '', error: false }}, successes: { ...state.successes, update: { message: 'Update successful.', success: true }}}
  }
}

标签: reactjsreact-redux

解决方案


对象初始化器中的扩展属性将它们自己的可枚举属性从提供的对象复制到新创建的对象上。如果新创建的对象中已经存在spread属性,则会自动替换。

换句话说,如果您有 2 个对象:const foo = {a: 1}const bar = {a: 2, b: 1}. 的结果{...foo, ...bar}将是{a: 2, b: 1}。因此,您可以看到分配的a属性是最后一个展开对象中的属性。

这正是你的情况。您必须考虑深度合并,因为您有一个用于错误和成功的多维结构。

根据您的错误结构,我将执行一个合并错误/成功的函数,如下所示:

const mergeMessages = (type, ...messages) =>
{
    return messages.reduce((carry, message) => {
        for (let [key, value] of Object.entries(message)) {
            if (!carry.hasOwnProperty(key) || value[type] === true) {
                carry[key] = value;
            }
        }

        return carry;
    }, {});
}

然后你可以像这样使用它:

const mapStateToProps = (store) => {
  return {
      // other fields
      errors: mergeMessages('error', store.prop1.errors, store.prop2.errors),
      successes: mergeMessages('success', store.prop1.successes, store.prop2.successes),
  }
}

推荐阅读