children useContext() 未使用当前值重新呈现

children with useContext() not rerendered with current value

我查看了所有标题相似的帖子,但没有找到任何可以帮助我理解和解决问题的帖子。

我已经创建了一个传递开关状态(切换或不切换)的上下文。问题是消费者 (children) 没有收到更改的上下文值(通过状态设置)。它是一个主值,一个布尔值,而不是 object 或数组,因此不需要重建。我不知道我做错了什么。

const Price = ({ showYearlyPrice }) => {
  function getPriceParts(showYearlyPrice: boolean){
    return showYearlyPrice ? "a" : "b";
  }

  const mainPrice = getPriceParts(showYearlyPrice);

  return (
    <>
      <div className="flex flex-row">
      <p className="text-grey text-sm">
        {mainPrice}
      </p>
    </>
  );
};

const PricingHeader = ({
  price,
}) => {
  // Subscribe to switch event
  const isToggled = useContext(SwitchContext);
  console.log(isToggled)// Only prints once, with default value every time

  return (
      <SubscribableSwitch color={sectionBackground}>
        <Section bg={sectionBackground} spacing={SectionSpacing.BOTTOM_ONLY}>
           <Price showYearlyPrice={isToggled as boolean} price={price}/>
        </Section>
      </SubscribableSwitch>
  );
};

export default PricingHeader;

然后是实际的 SubscribableSwitch 组件,其中的切换效果很好,并接收更新的上下文值。

export const SwitchContext = createContext(false); // Default value, if I put "potato" that's what gets printed in children

const Toggle = ({ toggle }) => {
  const isToggled = useContext(SwitchContext);
  return (
    <div className="flex justify-center mb-8 mt-2">
      <h2 onClick={toggle}>click me</h2>
      {!isToggled && (
            <span>
              Not toggled
            </span>
          )}
    </div>
  );
};

const SubscribableSwitch = ({color, children}) => {
  const [isToggled, setToggle] = useState(false);
  const toggle = () => setToggle((value) => !value);

  return (
      <SwitchContext.Provider value={isToggled}>
        <Toggle toggle={toggle}/>
        {children} // Where children is PricingHeader
      </SwitchContext.Provider>
  );
};

export default SubscribableSwitch;

我想通了,我觉得自己很蠢。

useContext 必须在 child 中使用。 A quote:

useContext(MyContext) only lets you read the context and subscribe to its changes. You still need a <MyContext.Provider> above in the tree to provide the value for this context.

我出错的确切位置是在打印 SubscribableSwitch 的组件的渲染函数中调用 useContext。代码应该是这样的:

const Price = () => {
  function getPriceParts(showYearlyPrice: boolean){
    return showYearlyPrice ? "a" : "b";
  }

  const isToggled = useContext(SwitchContext); 
  const mainPrice = getPriceParts(isToggled);

  return (
    <>
      <div className="flex flex-row">
      <p className="text-grey text-sm">
        {mainPrice}
      </p>
    </>
  );
};

const PricingHeader = ({
  price,
}) => {
 //useContext should NOT be here, I'm not a child of the Context Provider
  return (
      <SubscribableSwitch color={sectionBackground}>
        <Section bg={sectionBackground} spacing={SectionSpacing.BOTTOM_ONLY}>
           <Price price={price}/>
        </Section>
      </SubscribableSwitch>
  );
};

导出默认 PricingHeader;