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

React useContext路由跳转异常:从详情页返回首页触发TypeError

问题:从详情页返回首页时portfolios.map报错

问题场景

直接访问首页或从其他页面跳转首页时,组件能正常渲染所有portfolio;但从通过slug展示的详情页返回首页时,控制台抛出类型错误,页面无内容显示,刷新页面后恢复正常。

首页组件代码

const { portfolios, getPortfolios } = useContext(PortfolioContext);
  
useEffect(() => {getPortfolios()}, []);

return (...)

详情页组件代码

const { slug } = useParams();
const { portfolios, getPortfolioFromSlug } = useContext(PortfolioContext);
  
useEffect(() => {getPortfolioFromSlug(slug)}, []);

return (...)

报错信息

Uncaught TypeError: portfolios.map is not a function
    at Portfolio (Portfolio.js:15:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)

The above error occurred in the <Portfolio> component:

    at Portfolio (http://localhost:3000/static/js/bundle.js:1315:56)
    at Routes (http://localhost:3000/static/js/bundle.js:49405:5)
    at main
    at Router (http://localhost:3000/static/js/bundle.js:49338:15)
    at BrowserRouter (http://localhost:3000/static/js/bundle.js:48147:5)
    at PortfolioState (http://localhost:3000/static/js/bundle.js:1588:86)
    at App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

Context中的API函数代码

const getPortfolios = async () => {
    // API Call
    const response = await fetch(`http://${host}:${port}/api/portfolios/getportfolios`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        }
    });
    const jsonResponse = await response.json();
    setPortfolios(jsonResponse);
}

const getPortfolioFromSlug = async (slug) => {
    // API Call
    const response = await fetch(`http://${host}:${port}/api/portfolios/getportfolio/${slug}`, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json'
        }
    });
    const jsonResponse = await response.json();
    setPortfolios(jsonResponse);
}

问题根源

你在Context里用了同一个portfolios状态存储两种不同类型的数据:

  • getPortfolios返回的是数组,符合首页map遍历的需求
  • getPortfolioFromSlug返回的是单个对象,调用setPortfolios后会把原本的数组状态覆盖成对象

从详情页返回首页时,组件会先渲染当前Context里的portfolios(此时是对象),然后才会执行useEffect里的getPortfolios获取数组。这时候对对象调用map方法就会抛出类型错误。


修复方案

方案1:拆分状态(推荐,语义更清晰)

在Context里把列表和单个详情拆成两个独立状态,避免类型冲突:

// PortfolioContext内部定义状态
const [portfolioList, setPortfolioList] = useState([]);
const [currentPortfolio, setCurrentPortfolio] = useState(null);

// 修改API函数
const getPortfolios = async () => {
    const response = await fetch(`http://${host}:${port}/api/portfolios/getportfolios`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' }
    });
    const jsonResponse = await response.json();
    setPortfolioList(jsonResponse);
}

const getPortfolioFromSlug = async (slug) => {
    const response = await fetch(`http://${host}:${port}/api/portfolios/getportfolio/${slug}`, {
        method: 'GET',
        headers: { 'Content-Type': 'application/json' }
    });
    const jsonResponse = await response.json();
    setCurrentPortfolio(jsonResponse);
}

之后首页用portfolioList.map遍历,详情页直接使用currentPortfolio即可。

方案2:渲染时做类型校验

如果不想改动Context结构,可以在首页组件里先判断portfolios的类型,再执行遍历:

return (
    <div>
        {Array.isArray(portfolios) ? (
            portfolios.map(portfolio => (
                // 渲染单个portfolio项的逻辑
            ))
        ) : (
            // 加载状态或空提示
            <div>加载中...</div>
        )}
    </div>
)

额外优化建议

  • 初始化Context状态时,明确portfolios的初始值为[],避免初始状态类型不确定
  • 在API请求的useEffect里添加清理函数,防止组件卸载后仍更新状态(最佳实践)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 13:24:54