使用自定义钩子不触发 useState 更新

马克西姆·盖拉耶

我像这样为我的播放器制作了一个自定义钩子

const usePlayer = () => {
  const [volume, setVolume] = useState<number>(100);
  const playerRef = useRef<HTMLAudioElement | null>(null);
  const [playing, setPlaying] = useState<boolean>(false);
  useEffect(() => {
    console.log(volume);
  }, [volume]);
  return {
    playing,
    volume,
    setPlaying,
    setVolume,
    playerRef,
  };
};
export default usePlayer;

我正在监听另一个使用 userPlayer() 的组件的变化

const PlayerButton = () => {
  const { playerRef, volume } = usePlayer();

  useEffect(() => {
    console.log(volume);
    if (playerRef.current !== null) {
      playerRef.current.volume = volume / 100;
    }
  }, [volume]);
  return (
    <>
      <div className="lg:mr-2 flex align-middle">
        <audio ref={playerRef} preload="none">
        <source src="" type="audio/ogg"></source>
        <source src="" type="audio/mp3"></source>
      </audio>
      </div>
    </>
  );
};

export default PlayerButton

setVolume 在另一个组件中是这样调用的

  <input
     type="range"
     className="w-full"
     value={volume}
     onChange={(e) => setVolume(parseInt(e.target.value))}
     min={0}
     max={100}
         />

但是 useEffect 只在 usePlayer 组件内部触发,而不是在使用 usePlayer()

知道为什么吗?

特别的人

如果您在 PlayerButton 组件中使用 setVolume,它将触发 PlayerButton 中的 useEffect。

如果您在不同的组件中使用 setVolume,它不会触发 useEffect。

使用相同 Hook 的两个组件是否共享状态?不是。自定义 Hook 是一种重用有状态逻辑的机制(例如设置订阅和记住当前值),但是每次使用自定义 Hook 时,其中的所有状态和效果都是完全隔离的。

自定义 Hook 如何获得隔离状态?对 Hook 的每次调用都会获得隔离状态。因为我们直接调用 useFriendStatus,所以从 React 的角度来看,我们的组件只是调用了 useState 和 useEffect。而且正如我们之前了解到的,我们可以在一个组件中多次调用 useState 和 useEffect,并且它们将完全独立。

https://reactjs.org/docs/hooks-custom.html

如果想让 2 个组件共享状态,则需要使用 redux 或 useContext 来管理 store 中的状态。

https://reactjs.org/docs/hooks-reference.html#usecontext

useContext 和 Provider 的示例使用。

export const PlayerContext = createContext();
export const usePlayer = () => {
    const context = useContext(PlayerContext);
    if (!context && typeof window !== 'undefined') {
        throw new Error(`usePlayer must be used within a PlayerContext `);
    }
    return context;
};

export const PlayerProvider = ({ children }) => {

    const [ volume, setVolume ] = useState(100);

    return <PlayerContext.Provider value={{ volume, setVolume }}>{children}</PlayerContext.Provider>
}

您需要像这样使用提供程序包装您的应用程序。

<PlayerProvider><App /></PlayerProvider>

然后像这样使用它

const { volume, setVolume } = usePlayer()

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章