自定义挂钩,同步更新所有使用它的组件

Custom hook that updates all components that use it in sync

我正在尝试在使用自定义挂钩的 React 中创建一个 Switch 组件。我希望其他组件使用相同的自定义挂钩,以便在单击 Switch 时更新它们。为此,我创建了这个自定义挂钩:

function useToggle() {
  const [isToggled, setIsToggled] = useState(false);

  const toggle = React.useCallback(
    () => setIsToggled(state => !state),
    [setIsToggled],
  );

  return [isToggled, toggle];
}

然后在我想订阅这个自定义挂钩的 Switch 组件中:

const Switch = () => {
  const [isToggled, toggle] = useToggle();
  return (
         <Switch
          onChange={toggle as any}
          checked={isToggled as boolean}
          ...
        />

  );
}

然后在根据开关是否切换而改变值的组件中,我有:

const PricingHeader = () => {
   // Subscribe to switch's event
   const [isToggled, toggle] = useToggle();

   return (<Price showSpecialPrice={isToggled} />);
}

有问题吗?组件 独立更新 。我可以单击 switch,我看到它在切换时呈现不同的值,但我没有看到 Price 在切换时显示不同的价格被切换。 价格在我点击开关时完全不受影响。

不确定我做错了什么?我想象每次使用 useToggle 时返回的 isToggled 状态都是不同的。我正在尝试做的事情是否可行?

有可能,您可以通过 Context API:

分享您的 toggle 状态
const SwitchContext = createContext();

function useToggle() {
  return useContext(SwitchContext);
}

const Switch = () => {
  const [isToggled, toggle] = useToggle();
  return <button onClick={toggle}>{isToggled ? "ON" : "OFF"}</button>;
};

const Price = () => {
  const [isToggled] = useToggle();
  return <>The price {isToggled ? "IS TOGGLED" : "IS NOT TOGGLED"}</>;
};

export default function App() {
  const [isToggled, toggle] = useReducer((p) => !p, false);
  return (
    <SwitchContext.Provider value={[isToggled, toggle]}>
      <Switch />
      <Price />
    </SwitchContext.Provider>
  );
}

我可能建议您为此使用 React Context。您可以使用 createContext 创建一个 ToggleContext 并将其与 useContext -

一起使用

const { createContext, useContext, useState } = React

const ToggleContext = createContext(false)

function useToggle (initialState) {
  const [isToggle, setToggle] = useState(initialState)
  const toggle = () => setToggle(value => !value)
  return [isToggle, toggle]
}

function MyApp () {
  const [isToggle, toggle] = useToggle(false)
  return (
    <ToggleContext.Provider value={isToggle}>
      <p>Click any switch</p>
      <Switch onClick={toggle} />
      <Switch onClick={toggle} />
      <Switch onClick={toggle} />
    </ToggleContext.Provider>
  )
}

function Switch ({ onClick }) {
  const isToggle = useContext(ToggleContext)
  return <input type="checkbox" onClick={onClick} checked={isToggle} />
}

ReactDOM.render(<MyApp />, document.querySelector("main"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<main></main>