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

React Context无法更新:点击组件按钮后状态无变化求助

React Context不生效的问题修复

问题根源

你把DataModalContext.Provider放在了SingleProduct组件内部,但ModalProduct根本不在这个Provider的子组件树里——React Context只能给Provider的后代组件传递状态,所以ModalProduct完全接收不到SingleProduct里的状态更新。

另外你当前的Context设计也不对:只创建了Context,却没在需要共享状态的组件们的共同父组件里维护状态,反而在单个子组件里搞状态+Provider,这完全违背了Context的使用逻辑。

修复步骤

1. 重构Context,把状态和更新逻辑封装进去

先改DataModalContext.ts,让它包含状态和修改方法,方便所有组件共享:

import { createContext, useContext, useState, ReactNode } from "react";

// 定义Context的类型
interface DataModalContextType {
  isClicked: boolean;
  setIsClicked: (value: boolean) => void;
}

// 创建带默认值的Context(默认值仅在没有Provider时用)
const DataModalContext = createContext<DataModalContextType>({
  isClicked: false,
  setIsClicked: () => {},
});

// 封装Provider组件,用来包裹需要共享状态的组件树
export const DataModalProvider = ({ children }: { children: ReactNode }) => {
  const [isClicked, setIsClicked] = useState(false);

  return (
    <DataModalContext.Provider value={{ isClicked, setIsClicked }}>
      {children}
    </DataModalContext.Provider>
  );
};

// 写个自定义Hook,简化Context的调用
export const useDataModal = () => useContext(DataModalContext);

2. 在共同父组件里套上Provider

找到SingleProduct和ModalProduct的共同父组件(比如App或者它们所在的页面),用DataModalProvider把这俩组件包起来:

import { DataModalProvider } from './context/DataModalContext';
import SingleProduct from './SingleProduct';
import ModalProduct from './ModalProduct';

const ParentComponent = () => {
  // 保留你之前的Modal激活状态逻辑(如果需要的话)
  const [modalActive, setModalActive] = useState(false);

  return (
    <DataModalProvider>
      <SingleProduct 
        SingleProductModalActivator={setModalActive} 
      />
      <ModalProduct 
        activate={modalActive} 
        activator={setModalActive} 
      />
    </DataModalProvider>
  );
};

3. 修改SingleProduct,直接用Context的更新方法

删掉SingleProduct内部的Provider和本地状态,用自定义Hook来更新Context:

import { Skeleton } from '@mui/material';
import { useDataModal } from './../../../../context/DataModalContext';

interface ISingleProduct {
  imageSource?: string;
  imageText?: string;
  text?: string;
  SingleProductModalActivator?: React.Dispatch<React.SetStateAction<boolean>>;
}

const SingleProduct: React.FC<ISingleProduct> = ({ 
  imageSource, 
  imageText, 
  text, 
  SingleProductModalActivator 
}) => {
  const { setIsClicked } = useDataModal();

  const clickHandler = () => {
    // 激活Modal
    SingleProductModalActivator!(true);
    // 更新Context状态
    setIsClicked(true);
  };

  return (
    <div className='relative h-[330px] w-[230px] rounded-md shadow-lg p-[15px]'>
      <div className={"relative product-image w-[200px] h-[230px]"}>
        <div className='w-[200px] h-[200px] overflow-hidden rounded-md'>
          {imageSource ? (
            <img src={imageSource} alt={imageText} />
          ) : (
            <Skeleton variant='rectangular' width={200} height={200} className='rounded-md' />
          )}
        </div>
        <div className='bg-gray-300 absolute bottom-[10px] left-0 right-0 py-[1px] rounded-full'></div>
      </div>
      <div className={"product-text "}></div>
      <div 
        onClick={clickHandler} 
        className='absolute bottom-2 right-2 text-xs cursor-pointer select-none px-2 py-1 bg-cyan-700 text-white rounded-md'
      >
        more info
      </div>
    </div>
  );
};

export default SingleProduct;

4. 修改ModalProduct,读取Context状态

用自定义Hook获取Context里的状态就行:

import CloseIcon from '@mui/icons-material/Close';
import "./style.css";
import { useDataModal } from '../../../../context/DataModalContext';

interface IModalProduct {
  activate?: boolean;
  activator?: React.Dispatch<React.SetStateAction<boolean>>;
}

const ModalProduct: React.FC<IModalProduct> = ({ activate, activator }) => {
  const { isClicked } = useDataModal();

  const handleClick = () => {
    activator!(!activate);
  };

  return (
    <div className={`ModalProduct fixed top-0 bottom-0 left-0 right-0 ${activate ? "z-40 opacity-[100%]" : "z-[-10] opacity-0"} z-40`}>
      <div className={"bg-white h-[80vh] w-[80vw] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] rounded-md shadow-lg"}>
        <p>
          {isClicked ? "clicked" : "Single Product clicked"}
        </p>
      </div>
      <div 
        onClick={handleClick} 
        className='absolute top-5 left-5 cursor-pointer bg-white h-[40px] w-[40px] rounded-full shadow-md'
      >
        <CloseIcon className={'absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%]'} />
      </div>
    </div>
  );
};

export default ModalProduct;

关键说明

  • Context的Provider必须包裹所有需要共享状态的组件,这样它们才在同一个作用域里,能拿到同一个状态。
  • 用自定义Hook封装Context,既能少写重复代码,还能避免类型错误。
  • 状态得放在共同父组件(或者顶层Provider)里维护,不能在单个子组件里搞,不然其他组件根本拿不到更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:24:55