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

React组件间状态传递报错:onSelected不是函数问题排查

问题原因

你触发的错误本质是:实际被点击的FeatureMenu组件,并不是你在SelectionMenu里嵌套的那个实例。

点击CategoryButton时执行了history.push(SomeUrls.FeatureMenu),这会让React Router渲染一个全新的FeatureMenu组件——这个路由加载的组件完全独立于SelectionMenu里的那个,没有接收到onSelected props,所以onSelected是undefined,调用时自然会抛出"not a function"的错误。

解决方案

方案一:用本地状态控制显示(推荐,保持组件关联)

放弃路由跳转,改用本地状态控制FeatureMenu的显示/隐藏,这样始终是同一个嵌套的组件实例,能正常接收onSelected:

修改SelectionMenu.tsx:

export const SelectionMenu: React.FunctionComponent = () => {
    const history = useHistory();
    const [selected, setSelected] = useState<string>("");
    // 新增状态控制FeatureMenu显示
    const [showFeatureMenu, setShowFeatureMenu] = useState(false);
    const onSelected = (value: string) => setSelected(value);

    return (
        <SubMenu size="half">
            <SubMenuHead>
                <SubMenuTitle>Selection</SubMenuTitle>
                <Status>{selected}</Status>
            </SubMenuHead>
            <SelectList>
                <MenuHead className="sub-menu-heading">Select</MenuHead>
                {/* 把路由跳转改成切换显示状态 */}
                <CategoryButton onClick={() => setShowFeatureMenu(!showFeatureMenu)}>
                    A Category
                </CategoryButton>
                {/* 根据状态显示/隐藏FeatureMenu */}
                {showFeatureMenu && <FeatureMenu onSelected={onSelected} />}
            </SelectList>
        </SubMenu>
    );
};

这样点击分类按钮时,只是切换子菜单的显示状态,FeatureMenu始终嵌套在SelectionMenu中,能正常拿到onSelected函数,点击选项就能更新顶部的选中状态了。

方案二:用Redux共享状态(适合需要路由跳转的场景)

如果你必须保留路由跳转的逻辑,可以利用你已经在使用的Redux来共享选中状态,代替props传递函数:

  1. 修改Redux的Selection Slice,新增设置选中值的action:
// 假设你的slice文件路径是src/store/slices/selectionSlice.ts
import { createSlice } from '@reduxjs/toolkit';

const selectionSlice = createSlice({
  name: 'selection',
  initialState: {
    list: [],
    selectedValue: "" // 新增存储选中值的状态
  },
  reducers: {
    // 新增设置选中值的action
    setSelectedValue: (state, action) => {
      state.selectedValue = action.payload;
    }
  }
});

export const { setSelectedValue } = selectionSlice.actions;
export default selectionSlice.reducer;
  1. 更新SelectionMenu,从Redux获取选中值:
export const SelectionMenu: React.FunctionComponent = () => {
    const history = useHistory();
    // 从Redux获取选中值,替代本地state
    const selected = useAppSelector((state) => state.selection.selectedValue);

    return (
        <SubMenu size="half">
            <SubMenuHead>
                <SubMenuTitle>Selection</SubMenuTitle>
                <Status>{selected}</Status>
            </SubMenuHead>
            <SelectList>
                <MenuHead className="sub-menu-heading">Select</MenuHead>
                <CategoryButton onClick={() => history.push(SomeUrls.FeatureMenu)}>
                    A Category
                </CategoryButton>
            </SelectList>
        </SubMenu>
    );
};
  1. 修改FeatureMenu,直接调用Redux action更新状态:
import { useDispatch } from 'react-redux';
import { setSelectedValue } from '../store/slices/selectionSlice'; // 替换成你的slice路径

// 不再需要onSelected prop
type Props = {};

export const FeatureMenu: React.FunctionComponent<Props> = () => {
    const history = useHistory();
    const dispatch = useDispatch();
    const selections = useAppSelector((state) => state.selection.list);
    const feature = useMemo(
        () => uniq(selections.map((m) => m.aFeature)),
        [selections]
    );

    const handleClick = (value: string) => {
        // 调用Redux action更新选中值
        dispatch(setSelectedValue(value));
        // 可以跳回SelectionMenu页面
        history.goBack();
    };

    return (
      <SelectMenu variants={selectMenu} initial="hidden" animate="visible" exit="hidden">
        <SelectList>
            <MenuHeading className="select-menu-heading">Feature</MenuHeading>
            {feature.map((f) => (
                    <SelectListButton
                        key={`${f}`}
                        onClick={() => handleClick(`${f}`)}
                    >
                        {`${f}`}
                    </SelectListButton>
                ))
            )}
        </SelectList>
      </SelectMenu>
    );
};

这种方式通过Redux全局共享状态,不管FeatureMenu是路由渲染还是嵌套渲染,都能同步更新选中值,SelectionMenu也能实时获取最新状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 04:22:51