我像这样为我的播放器制作了一个自定义钩子
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()
的第二个组件中触发
知道为什么吗?
答案 0 :(得分:1)
如果您在 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 个组件共享 state,你需要使用 redux 或者 useContext 来管理 store 中的 state。
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()