组件监听上下文。每次上下文更新都会触发一次重新呈现。如果我已经得到了正确的值,我可以停止监听上下文吗?我想在此上下文更改时停止进一步的组件更新举个例子
const {contextValue, setContextValue}= useContext(MyContext) if (contextValue == 'stop listen') {stop listening}
这可能吗?
hmmo2u0o1#
没有办法将一个useContext调用引入到一个自定义钩子中,当上下文值改变时,它不会导致重新呈现。但是,我们可以在一个更高阶的组件中实现类似的功能。
useContext
const withContextValue = Component => (props) => { const context = useContext(MyContext); const contextRef = useRef(context); if (contextRef.current.contextValue !== 'stop listen') contextRef.current = context; return <Component {...props} context={contextRef.current} />; };
如果你传递一个memoized组件给withContextValue,你将收到一个组件,它将在每次上下文值更改时重新呈现,但memoized组件将不会重新呈现,这与在memoized组件内部调用useContext的情况不同。上面的模式可能不太好用,并且不能完全消除重新呈现。为了获得更好的开发人员体验,您可能希望尝试订阅模式,其中上下文的每个消费者都可以定义导致重新呈现的更改。react-redux使用这种模式。将上下文值定义为可变对象。
withContextValue
react-redux
class ContextValue { constructor() { this.subscribers = []; this.contextValue = ''; } setContextValue(action) { const prevValue = this.contextValue; this.contextValue = typeof action === 'function' ? action(this.contextValue) : action; if (prevValue !== this.contextValue) this.subscribers.forEach(subscriber => subscriber(this.contextValue)); } subscribe(subscriber) { this.subscribers.push(subscriber); return () => void (this.subscribers = this.subscribers.filter(sub => sub !== subscriber)); } } export const Provider = () => { const context = useRef(new ContextValue()).current; return <MyContext.Provider value={context}>{children}</MyContext.Provider> }; export const useMyContext = (equalityFn = () => false) => { const [, rerender] = useReducer(() => ({}), {}); const context = useContext(MyContext); const equalityFnRef = useRef(equalityFn); equalityFn.current = equalityFn; useEffect( () => context.subscribe(newValue => { if (!equalityFnRef.current(context.contextValue, newValue)) rerender(); }), [context.subscriber, context.contextValue] ); return context; };
然后,您可以定义任何相等函数来限制逐个消费者的重新呈现,就像Redux的useSelector一样。
useSelector
const {contextValue, setContextValue}= useMyContext(prevValue => prevValue === 'stop listen');
注意,这个模式将停止不必要的重新呈现,但不会阻止组件在其他原因导致重新呈现时阅读最新的上下文值。如果需要停止接收新值,则需要将钩子 Package 在额外的记忆层中。
aurhwmvo2#
useContext()的消费者将始终在上下文值更改时重新呈现。“即使祖先使用React.memo或shouldComponentUpdate,重新渲染仍然会使用useContext从组件本身开始。如果您不希望上下文更改总是触发组件重新呈现,那么有一个很好的机会,那就是使用其他一些维护该状态的方法更适合您的用例。请参阅useContext React文档了解更多信息。
useContext()
2条答案
按热度按时间hmmo2u0o1#
没有办法将一个
useContext
调用引入到一个自定义钩子中,当上下文值改变时,它不会导致重新呈现。但是,我们可以在一个更高阶的组件中实现类似的功能。如果你传递一个memoized组件给
withContextValue
,你将收到一个组件,它将在每次上下文值更改时重新呈现,但memoized组件将不会重新呈现,这与在memoized组件内部调用useContext
的情况不同。上面的模式可能不太好用,并且不能完全消除重新呈现。为了获得更好的开发人员体验,您可能希望尝试订阅模式,其中上下文的每个消费者都可以定义导致重新呈现的更改。
react-redux
使用这种模式。将上下文值定义为可变对象。
然后,您可以定义任何相等函数来限制逐个消费者的重新呈现,就像Redux的
useSelector
一样。注意,这个模式将停止不必要的重新呈现,但不会阻止组件在其他原因导致重新呈现时阅读最新的上下文值。如果需要停止接收新值,则需要将钩子 Package 在额外的记忆层中。
aurhwmvo2#
useContext()
的消费者将始终在上下文值更改时重新呈现。“即使祖先使用React.memo或shouldComponentUpdate,重新渲染仍然会使用useContext从组件本身开始。
如果您不希望上下文更改总是触发组件重新呈现,那么有一个很好的机会,那就是使用其他一些维护该状态的方法更适合您的用例。
请参阅useContext React文档了解更多信息。