当React Hooks中的redux状态改变时,道具不更新

时间:2019-08-03 20:38:35

标签: reactjs redux react-redux state

我正在尝试在React Hooks项目上实现Redux,但是它似乎不能很好地工作。我在这里做错什么了吗?

reducer.js

const initialState = {
    educations: []
};

export default function home(state = initialState, action){
    switch(action.type){
        case GET_EDUCATIONS: {
            state.educations = action.payload;
            return state;
        }
        default:
            return state;
    }
}

action.js

import * as types from '../constans/home';

export const getEducations = () => {
    return dispatch => {
        const edus = [
            {value: 1, name: 'Bachelor'},
            {value: 2, name: "Master"}
        ]

        dispatch({
            type: types.GET_EDUCATIONS,
            payload: edus
        })
    }
}

组件

import React, {useEffect} from 'react';
import {connect} from 'react-redux';
import {getEducations} from '../../redux/actions/home';

function Header({educations, getEducations}) { 
    useEffect(() => {
        getEducations(); //calling getEducations()
    }, [])

    useEffect(() => {
        console.log(educations) //console educations after every change
    })

    return (
        <div className="main-header">
        </div>
    )
}

const mapStateToProps = (state) => {
    return {
        educations: state.home.educations
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        getEducations: () => { dispatch(getEducations())}
    }
}

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

Header函数中的Education属性始终是一个空数组,如initialState中所示。 当我使用Redux Devtools检查浏览器时,它显示状态包含数组中的这两个对象。 enter image description here

因此,无论是否更改redux状态,组件的属性都将保持为initialState。

5 个答案:

答案 0 :(得分:4)

redux中,应避免直接改变减速器的状态。不要做类似state.reducers = blah的事情。为了使redux知道您正在尝试对state进行更新,您需要返回一个全新的状态对象。遵循这些原则,减速器将正确更新,并且组件将获取新数据。

Reducer.js

const initialState = {
    educations: []
};

export default function home(state = initialState, action){
    switch(action.type){
        case GET_EDUCATIONS: {
            return {
               ...state,
               educations: action.payload
            };
        }
        default:
            return state;
    }
}

在上面的代码中,我们返回一个新的状态对象。它将包括现有state以及...state中的所有内容,而我们只需使用educations更新action.payload属性。

答案 1 :(得分:1)

可以尝试用这种方式编写的减速器:

const initialState = {
        educations: []
    };

export default function home(state = initialState, action){
    switch(action.type){
        case GET_EDUCATIONS: 
        return {
            ...state, educations:action.payload
        }

        default:
            return state;
    }
}

答案 2 :(得分:0)

您似乎正在简化化简器中的状态。如果更新了某些内容,reducer应该始终返回一个新的状态对象。

您可以按照上述答案的建议进行操作,但是我建议您使用immer(https://www.npmjs.com/package/immer)或immutable.js之类的软件包来防止任何错误。如果状态对象具有一些深层嵌套的属性,则使用传播语法可能很危险,而且很难100%确保没有意外地对某些内容进行突变,尤其是随着应用程序大小的增加。

答案 3 :(得分:0)

在我输入此字词时,您似乎已解决了这个问题-我决定将其张贴,因为这可能会有所帮助。

在克里斯托弗·恩戈(Christopher Ngo)所提到的内容之上,以下示例概述了如何与商店互动以创建新的教育,然后在单独的组件中进行查看。

Edit modest-fermat-98s0r

干杯!

答案 4 :(得分:0)

我一直遇到这个问题,然后用 CLEAR 和 GET/SET 状态解决它。这确保了状态调用的重置。

Reducers.js

const initialState = {
    educations: []
};

export default function home(state = initialState, action){
    switch(action.type){
        case GET_EDUCATIONS: {
            return {
               ...state,
               educations: action.payload
            };
        }
        case CLEAR_EDUCATIONS: {
            return initialState;
        }
        default:
            return state;
    }
}

Hooks.js

...
const clearEducation = () => {
  dispatch({ type: CLEAR_EDUCATION });
}
   const getEducations = (payload) => {
      clearEducation(); // this clearing of the state is key fire re-render
      dispatch({ type: GET_EDUCATIONS, payload });
   };

}