reactjs 停止监听上下文React

zzzyeukh  于 2023-04-11  发布在  React
关注(0)|答案(2)|浏览(103)

组件监听上下文。每次上下文更新都会触发一次重新呈现。如果我已经得到了正确的值,我可以停止监听上下文吗?我想在此上下文更改时停止进一步的组件更新
举个例子

const {contextValue, setContextValue}= useContext(MyContext)
if (contextValue == 'stop listen') {stop listening}

这可能吗?

hmmo2u0o

hmmo2u0o1#

没有办法将一个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使用这种模式。
将上下文值定义为可变对象。

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一样。

const {contextValue, setContextValue}= useMyContext(prevValue => prevValue === 'stop listen');

注意,这个模式将停止不必要的重新呈现,但不会阻止组件在其他原因导致重新呈现时阅读最新的上下文值。如果需要停止接收新值,则需要将钩子 Package 在额外的记忆层中。

aurhwmvo

aurhwmvo2#

useContext()的消费者将始终在上下文值更改时重新呈现。
“即使祖先使用React.memo或shouldComponentUpdate,重新渲染仍然会使用useContext从组件本身开始。
如果您不希望上下文更改总是触发组件重新呈现,那么有一个很好的机会,那就是使用其他一些维护该状态的方法更适合您的用例。
请参阅useContext React文档了解更多信息。

相关问题