диспетчерские действия не будут вызывать рендеринг при использовании комбинированных элементов - PullRequest
0 голосов
/ 07 января 2019

Когда я не использую combReducers:

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;
}

При внесении предложенных изменений (при замене редуктора и комбайнера я получаю новую ошибку:

enter image description here

мой редуктор теперь выглядит так:

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;
    }
}

1 Ответ

0 голосов
/ 07 января 2019

Возможно, проблема в том, как вы используете 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» для получения более подробной информации

...