我希望这个钩子仅在实际结果发生变化时(即 isLoading、isPlaying、isPaused)触发任何订阅组件中的重新渲染:
export const usePlaybackState = (): {
isLoading: boolean
isPlaying: boolean
isPaused: boolean
} => {
const { state: stateFromLib } = usePlaybackStateLib()
const stateRef = useRef({
isLoading: false,
isPlaying: false,
isPaused: false,
})
const newState = mapInternalPlayerStateToPlaybackProps(stateFromLib, stateRef.current)
const memoizedState = useMemo(() => {
if (
newState.isLoading !== stateRef.current.isLoading ||
newState.isPlaying !== stateRef.current.isPlaying ||
newState.isPaused !== stateRef.current.isPaused
) {
console.log('>>>State changed:', newState)
stateRef.current = newState
}
return stateRef.current
}, [newState.isLoading, newState.isPlaying, newState.isPaused])
console.log('>>>memoizedState', memoizedState, stateFromLib)
return memoizedState
}
export const [PlaybackStateProvider, usePlaybackStateContext] = constate(usePlaybackState)
但是…stateFromLib 非常嘈杂,每次它发生变化时,即使结果根本没有变化,我也会收到大量的重新渲染。就这样(反复)
>>>memoizedState {"isLoading": true, "isPaused": false, "isPlaying": false} buffering
>>>memoizedState {"isLoading": true, "isPaused": false, "isPlaying": false} ready
>>>isPlaying false false true
>>>memoizedState {"isLoading": true, "isPaused": false, "isPlaying": false} buffering
>>>memoizedState {"isLoading": true, "isPaused": false, "isPlaying": false} ready
>>>isPlaying false false true
知道为什么吗?感觉一定是因为我正在返回一个对象,但尽管记忆应该处理这个问题
自定义挂钩可帮助您重用逻辑。它们防止复制/粘贴。他们没什么特别的。 与在组件主体中调用整个代码相同。
如果自定义挂钩中的某些内容导致重新渲染,则组件将重新渲染。你返回什么并不重要
但是有几种方法可以用来达到类似的效果。
const PlaybackContext = React.createContext<your_value_type_here>()
const PlaybackProvider = ({children}: {children: React.ReactNode}) => {
const { state: stateFromLib } = usePlaybackStateLib()
const newState = mapInternalPlayerStateToPlaybackProps(stateFromLib, stateRef.current)
const value = useMemo(() => {
return {
loading: newState.loading,
isPlaying: newState.isPlaying,
isPaused: newState.isPaused
}
}, [newState.isLoading, newState.isPlaying, newState.isPaused])
return <PlaybackContext.Provider value={value}>{children}</PlaybackContext.Provider>
}
const usePlaybackContext = () => React.useContext(PlaybackContext)
现在
PlaybackProvider
每次都会重新渲染,但是使用其值的组件仅在其值发生变化时才会重新渲染。仅当这 3 种状态中至少有一种发生变化时,它才会发生变化。
用途:
<PlaybackProvider><MyComponent/><AnotherComponent/>...</PlaybackProvider>
里面
MyComponent
:
const playbackState = usePlaybackContext()
PlaybackProvider
应该包装所有使用公共状态的内容!