React & Redux,更新状态,错误:在调度之间检测到状态突变

Posted

技术标签:

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

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

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

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

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

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

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

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

    在 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 的模块中定义。它返回一个承诺。 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

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

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

进行深度复制

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

【讨论】:

以上是关于React & Redux,更新状态,错误:在调度之间检测到状态突变的主要内容,如果未能解决你的问题,请参考以下文章

React,redux 组件不会在路由更改时更新

React/Redux 存储更新但组件未重新渲染

Redux - 状态正在更新,但 React 组件没有

REACT + REDUX:在 redux 状态更改时 mapStateToProps 更新状态,但视图未按照新状态呈现

当 redux 状态更新时,React 组件不更新

根据 React-Redux 状态的动态页面不更新渲染数据