首页 > 解决方案 > 使用 combineReducers 时调度动作不会触发渲染

问题描述

当我不使用 combineReducers 时:

const store = createStore<StoreState,any,any,any>(pointReducer, {
    points: 1,
    languageName: 'Points',
});

function tick() {
    store.dispatch(gameTick());
    requestAnimationFrame(tick)
}

tick();

一切正常,我的组件更新。但是,当我这样做时:

const reducers = combineReducers({pointReducer}) as any;

const store = createStore<StoreState,any,any,any>(reducers, {
    points: 1,
    languageName: 'Points',
});

商店确实更新了(通过控制台日志记录检查)但是组件没有呈现更改,我不知道为什么!

减速机:

export function pointReducer(state: StoreState, action: EnthusiasmAction): StoreState {
    switch (action.type) {
        case INCREMENT_ENTHUSIASM:
            return { ...state, points: state.points + 1 };
        case DECREMENT_ENTHUSIASM:
            return { ...state, points: Math.max(1, state.points - 1) };
        case GAME_TICK:
            return { ...state, points: state.points + 1 };
        default:
            return state;
    }
}

和组件:

export interface Props {
    name: string;
    points: number;
    onIncrement: () => void;
    onDecrement: () => void;
}

class Points extends React.Component<Props, object> {

    constructor(props: Props) {
        super(props);
    }

    render() {
        const { name, points, onIncrement, onDecrement } = this.props;

        return (
            <div className="hello">
                <div className="greeting">
                    Hello {name + points}
                </div>
                <button onClick={onDecrement}>-</button>
                <button onClick={onIncrement}>+</button>
            </div>
        );
    }
}

export default Points;

容器:

export function mapStateToProps({ points, languageName }: StoreState) {
    return {
        points: points,
        name: languageName,
    }
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
    return {
        onIncrement: () => dispatch(actions.incrementEnthusiasm()),
        onDecrement: () => dispatch(actions.decrementEnthusiasm())
    }
}

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

存储状态:

export interface StoreState {
    languageName: string;
    points: number;
    food: number;
    wood: number;
}

进行建议的更改时(更改减速器和组合减速器,我收到一个新错误:

在此处输入图像描述

我的减速器现在看起来像:

export function pointReducer(state: 1, action: EnthusiasmAction) {
    switch (action.type) {
        case INCREMENT_ENTHUSIASM:
            return state + 1;
        case DECREMENT_ENTHUSIASM:
            return Math.max(1, state - 1);
        case GAME_TICK:
            return state + 1;
        default:
            return state;
    }
}

标签: reactjstypescriptreduxreact-redux

解决方案


问题可能在于您如何使用combineReducers,而不是您如何编写mapState函数。

我猜你的mapState函数看起来像:

const mapState = (state) => {
    return {
        points : state.points
    }
}

当您单独使用时,这可以正常工作pointsReducer,因为您的状态具有state.points.

然而,当你使用combineReducers你现在的方式时,你给自己制造了两个问题:

  • 您正在命名状态字段state.pointsReducer,而不是state.points
  • pointsReducer进一步将数据嵌套为points

因此,您想要的实际数据位于state.pointsReducer.points,而组件期望它位于state.points

要解决此问题,您应该更改调用方式combineReducers,并将pointsReducer定义更改为仅跟踪数据而不进行嵌套:

export function pointReducer(state: 1, action: EnthusiasmAction): StoreState {
    switch (action.type) {
        case INCREMENT_ENTHUSIASM:
            return state + 1
        case DECREMENT_ENTHUSIASM:
            return Math.max(1, state - 1);
        case GAME_TICK:
            return state.points + 1;
        default:
            return state;
    }
}

// later

const rootReducer = combineReducers({
    points : pointsReducer,
    languageName : languageNameReducer,
});

有关更多详细信息,请参阅有关“使用”的Redux 文档页面combineReducers


推荐阅读