【问题标题】:React & Redux, Update state, Error: A state mutation was detected between dispatchesReact & Redux,更新状态,错误:在调度之间检测到状态突变
【发布时间】:2019-12-25 23:46:03
【问题描述】:

我遇到的问题是我的保存数据往返。

错误:browser.js:34 Uncaught (in promise) Invariant Violation:在路径 profile.user.alias 中检测到调度之间的状态突变。

我是 React 和 Redux 的新手,但我认为我已经完成了一切。我错过了什么?

  1. 我在组件中创建一个本地状态并分配从 mapStateToProps 返回的对象。

  2. 我在文本字段的 onChange 上设置状态。

  3. 在保存单击时,我调用 mapDispatchToProps 中定义的操作,将本地状态传递给它。注意,映射的动作是一个 Thunk 函数,因为我使用 REST Api 在服务器上保存日期。

  4. 服务器保存数据并返回相同的对象,并填写新的 Id 等。

  5. 在 fetch.then() 中,我调度一个动作,传递从服务器返回的对象。

错误在调度线上。

export function setUserProfile (profile) {
    return function(dispatch) {
        return setProfile(profile)  <-- the API call
            .then(p => {
                dispatch(handleSetProfileSuccess(p));
            })
            .catch(error => {
                throw error;
            });
    };

从昨天开始我就一直在努力解决这个错误。我已经尝试了所有我发现的技巧,包括从 Redux-Starter-Kit 更改为 createReducer。

我已确保我在“set”中使用的对象、动作、reducer 等完全相同的链与在“get”中有效的动作相同。

export function handleSetProfileSuccess (profile) {
    return { type: types.SET_USER_PROFILE_SUCCESS, profile };
}


export function setUserProfile (profile) {
    return function(dispatch) {
        return setProfile(profile)   <--- the api call with fetch
            .then(p => {
                dispatch(handleSetProfileSuccess(p));
            })
            .catch(error => {
                throw error;
            });
    };

// the action is never dispatched on save since the error is on the dispatch line above.
// the Redux way
export default function profileReducer(state = {}, action) {
    switch (action.type) {
        case types.GET_USER_PROFILE_SUCCESS:
            return { ...state, ...action.profile };
        case types.SET_USER_PROFILE_SUCCESS:
            return { ...state, ...action.profile };
        default:
            return state;
    }
} 


// the redux-starter-kit way
const profileReducer=createReducer({}, {
    GET_USER_PROFILE_SUCCESS: (state, action) => state=action.profile,
    SET_USER_PROFILE_SUCCESS: (state,action) => state=action.profile
});

整个往返行程有效。新数据保存在服务器上,服务器返回的对象是正确的。 .then() 调用中的参数“p”确实包含正确的数据。但它在调用

时崩溃
dispatch(handleSetProfileSuccess(p));

编辑:这是 profile.js 中的代码 sn-ps

// profile.js
state = { ...this.props.profile };

// on save click handler
setData = e => {
    e.preventDefault();

    // validate stuff here
    this.props.setProfile(this.state).then(() => {
        this.setState(prevState => ({
            ...prevState,
            ...this.props.profile
        }));
    });
};

export function mapStateToProps(state) {
    return {
        user: state.user, 
        profile: state.profile 
    };
}

const mapDispatchToProps = {
    getProfile: profileActions.getUserProfile,
    setProfile: profileActions.setUserProfile
};

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Profile);

请帮忙。我别无选择。

【问题讨论】:

  • 不确定这是否是问题所在,但这不需要返回:return setProfile
  • 是否会为类型 SET_USER_PROFILE_SUCCESS 调用减速器?
  • 没有。由于错误在调度调用中,因此永远不会到达减速器。
  • 您能否显示您可能正在访问该状态路径的任何其他位置?您是在 mapState 函数中还是在组件文件中阅读它? (另外,我要指出,这正是 RSK 在默认情况下添加“突变检测”中间件的原因 - 以捕获这些类型的错误。)
  • setProfile 函数在所有 API 的模块中定义。它返回一个承诺。

标签: javascript reactjs redux react-redux


【解决方案1】:

很可能你正在改变 react-redux 传递的 prop。

检查你使用props.profileprops.user的所有代码,像下面这样的代码可能是罪魁祸首

props.profile.friends.splice(0, 1);

【讨论】:

    【解决方案2】:

    当您对接收到的道具进行突变并使用该突变道具分派操作时,会发生状态突变错误。因此,要进行此类调度,请在接收 props 时将其复制到本地 state,对 state 进行更改并使用 state 调度 action。

    如果收到的 props 是嵌套对象,请使用
    JSON.parse(JSON.stringify());

    进行深度复制

    因此,在您的代码中,在进行分派之前,将道具复制到一个状态并使用该状态进行分派。

    【讨论】:

      猜你喜欢
      • 2017-04-24
      • 1970-01-01
      • 2017-11-04
      • 2019-10-13
      • 1970-01-01
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 2016-12-08
      相关资源
      最近更新 更多