You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useReducer中action对象为undefined问题求助(React Router v6)

问题:React Router v6中通过Context传递dispatch修改状态失败

我正在使用React Router v6,尝试通过Context传递的dispatch函数修改Context中的状态变量,预期流程是:

  1. 选项值变更 -> 调用dispatch
  2. reducer读取action值并修改状态变量
  3. 状态变量通过Context传递给组件使用

但实际出现问题:reducer函数无法获取action对象,读取action时触发"cannot read properties of undefined"错误。


相关代码

main.tsx

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: filmsLoader,
    children: [
      {
        path: "/",
        element: <FilmsGrid />
      }
    ]
  }
]);

ReactDOM.createRoot(document.getElementById('root')!).render(
  <CssBaseline>
    <Provider>
      <RouterProvider router={router} />
    </Provider>
  </CssBaseline>
);

FilterContext文件

import React, { createContext, useContext, useReducer } from "react";

const FilterContext = createContext('popular');
const FilterReducerContext = createContext(null);

function filterReducer({state, action}) {
    console.log(action.type); // 此处为undefined 
    switch (action) {
        case "popular": {
            return {
                filterState: "popular"
            };
        }
        case "release-date": {
            return {
                filterState: "release-date"
            };
        }
        default: return state;
    }
}

export default function Provider({ children }) {
    const [filterState, dispatch] = useReducer(filterReducer, 'popular');

    return (
        <FilterContext.Provider value={filterState}>
            <FilterReducerContext.Provider value={dispatch}>
                { children }
            </FilterReducerContext.Provider>
        </FilterContext.Provider>
    );
}

export function useFilterContext() {
    return useContext(FilterContext);
}
export function useFilterReducer() {
    return useContext(FilterReducerContext);
}

SortType组件

import { Box, FormControl, InputLabel, MenuItem, Select } from "@mui/material";
import { useFilterContext, useFilterReducer } from "../../../FilterContext";

function SortType() {
    const filterState = useFilterContext();
    const dispatch = useFilterReducer();

    const changeSortType = (event) => {
        dispatch({
            type: event.target.value
        })
    };

    return (
        <Box 
        width={'100%'}
        sx={{
            padding: 2
        }}
        >
            <FormControl
            fullWidth
            >
                <InputLabel
                    id={'sortType-select'}
                    sx={{
                        "&.MuiInputLabel-root": {
                            left: -12
                        }
                    }}
                >Sort by:</InputLabel>
                <Select
                labelId="sortType-select"
                variant="standard"
                onChange={event => changeSortType(event)}
                value={filterState}
                >
                    <MenuItem value={'popular'}>Popular</MenuItem>
                    <MenuItem value={'release-date'}>Release date</MenuItem>
                </Select>
            </FormControl>
        </Box>
    );
}

export default SortType;

问题原因及修复方案

1. Reducer参数写法错误

useReducer的reducer函数接收两个独立参数:当前状态state和动作对象action,而非一个包含两者的对象。你的代码里用了{state, action}解构,导致实际参数不匹配,action被解析为undefined。

2. 状态类型不统一

初始状态是字符串'popular',但reducer返回的是{filterState: "..."}对象,类型不一致会导致后续状态读取异常。

3. Reducer中action判断逻辑错误

你在switch里直接判断action,但dispatch传递的是{type: value}对象,应该判断action.type。


修正后的代码

方案一:保持状态为字符串类型

import React, { createContext, useContext, useReducer } from "react";

const FilterContext = createContext('popular');
const FilterReducerContext = createContext<React.Dispatch<{type: string}>>(null);

// 修正reducer参数为独立的state和action
function filterReducer(state: string, action: {type: string}) {
    console.log(action.type);
    switch (action.type) {
        case "popular":
            return "popular";
        case "release-date":
            return "release-date";
        default:
            return state;
    }
}

export default function Provider({ children }) {
    const [filterState, dispatch] = useReducer(filterReducer, 'popular');

    return (
        <FilterContext.Provider value={filterState}>
            <FilterReducerContext.Provider value={dispatch}>
                { children }
            </FilterReducerContext.Provider>
        </FilterContext.Provider>
    );
}

export function useFilterContext() {
    return useContext(FilterContext);
}
export function useFilterReducer() {
    return useContext(FilterReducerContext);
}

方案二:使用对象存储状态

import React, { createContext, useContext, useReducer } from "react";

// 初始状态改为对象
const FilterContext = createContext({filterState: 'popular'});
const FilterReducerContext = createContext<React.Dispatch<{type: string}>>(null);

function filterReducer(state: {filterState: string}, action: {type: string}) {
    switch (action.type) {
        case "popular":
            return {filterState: "popular"};
        case "release-date":
            return {filterState: "release-date"};
        default:
            return state;
    }
}

export default function Provider({ children }) {
    const [filterState, dispatch] = useReducer(filterReducer, {filterState: 'popular'});

    return (
        <FilterContext.Provider value={filterState}>
            <FilterReducerContext.Provider value={dispatch}>
                { children }
            </FilterReducerContext.Provider>
        </FilterContext.Provider>
    );
}

export function useFilterContext() {
    return useContext(FilterContext);
}
export function useFilterReducer() {
    return useContext(FilterReducerContext);
}

选择方案二时,SortType组件需要调整状态读取方式:

const { filterState } = useFilterContext();

内容的提问来源于stack exchange,提问作者Didi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:54:54