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

Next.js 13 + React全局Context状态传递异常问题排查

问题描述

使用Next.js 13 + React开发应用,页面展示项目列表,点击项目时控制台能正常打印Item clicked,但无法将SelectableItems.js中的状态同步到SelectedItemContext.js的全局上下文。

App.tsx位于/pages目录,尝试过将其作为_app,也试过.js和.tsx两种配置,检查过组件层级,理论上应该能生效。目前点击列表项能触发onClick并记录项名称,但状态仅能在本地更新,无法全局同步。

代码展示

SelectableItems.js

import React from 'react';
import { useSelectedItem } from './SelectedItemContext';

const SelectableItem = ({ name }) => {
    const { selectedItem, setSelectedItem } = useSelectedItem();

    const handleClick = () => {
        const newItem = name === selectedItem ? null : name;
        setSelectedItem(newItem);

        console.log(`Item clicked: ${name}. New selected item: ${newItem}`);
    };

    return (
        <div
            className={`selectable-item ${name === selectedItem ? 'selected' : ''}`}
            onClick={handleClick}
        >
            {name}
        </div>
    );
};

export default SelectableItem;

App.tsx

import React from 'react';
import Header from '../app/page_items/zones/header';
// import { MainComponent } from '../app/page_items/lists/ListParser'
// import SelectableItem from '../app/page_items/lists/selecteditem/SelectableItems'
import { SelectedItemProvider } from '../app/page_items/lists/selecteditem/SelectedItemContext';
import Content from '../app/layout'

function App() {
    const [databaseName, setDatabaseName] = useState("");
    const [searchTerm, setSearchTerm] = useState("");

    return (
        <SelectedItemProvider>
            <div>
                <Header />
                <Content />
            </div>
        </SelectedItemProvider>
    );
};

SelectedItemContext.js

import React, { createContext, useContext, useState, useEffect } from 'react';
console.log("SelectedItemProvider loading!");

const SelectedItemContext = createContext({ selectedItem: null, setSelectedItem: () => { console.log('Default setSelectedItem invoked'); } });

export const useSelectedItem = () => {
    const context = useContext(SelectedItemContext);
    if (!context) {
        throw new Error("useSelectedItem must be used within a SelectedItemProvider");
    }
    return context;
};

export const SelectedItemProvider = ({ children }) => {
    const [selectedItem, setSelectedItem] = useState(null);

    useEffect(() => {
        console.log("SelectedItemProvider Mounted/Updated");
    }, []);

    useEffect(() => {
        console.log("Updated selectedItem:", selectedItem);
    }, [selectedItem]); // This hook runs every time selectedItem changes

    return (
        <SelectedItemContext.Provider value={{ selectedItem, setSelectedItem }}>
            {children}
            <div>Is this provider even rendering?</div>
        </SelectedItemContext.Provider>
    );
};

export default SelectedItemContext;

排查与解决建议

  • 确认Provider作用范围:检查SelectableItem组件是否确实在SelectedItemProvider包裹的Header或Content子组件树中。如果组件在Provider范围外,将无法获取全局上下文状态。
  • 适配Next.js 13 Pages Router规范:你的App.tsx在/pages目录,属于Pages Router模式,全局上下文Provider应该放在/pages/_app.tsx中,而非自定义的App.tsx。修改后的_app.tsx示例:
    // /pages/_app.tsx
    import React from 'react';
    import { SelectedItemProvider } from '../app/page_items/lists/selecteditem/SelectedItemContext';
    
    export default function MyApp({ Component, pageProps }) {
      return (
        <SelectedItemProvider>
          <Component {...pageProps} />
        </SelectedItemProvider>
      );
    }
    
  • 验证状态更新日志:点击列表项时,查看控制台是否打印Updated selectedItem: xxx。如果未打印,说明调用的是上下文默认的setSelectedItem函数,证明组件不在Provider范围内。
  • 修复App.tsx语法错误:App.tsx中使用了useState但未导入,需添加import React, { useState } from 'react';,避免组件报错影响状态逻辑。
  • 检查Provider嵌套问题:确认是否存在多个SelectedItemProvider嵌套,导致子组件获取到的是内层Provider的局部状态,而非全局状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:53:10