我在我的Reaction应用程序中有一个定制的钩子,可以处理向后导航操作(POP).它工作得很好,但我认为useCallbackuseEffect做的是完全一样的事情.

以下是我的代码:

export default function Index(onBackEvent?: () => void) {
  const handleBackPress = useCallback((e: PopStateEvent) => {
    e.preventDefault()
    window.history.pushState(null, '', window.location.pathname)
    if (onBackEvent) onBackEvent()
  }, [onBackEvent])

  useEffect(() => {
    window.history.pushState(null, '', window.location.pathname)
    window.addEventListener('popstate', handleBackPress)
    return () => {
      window.removeEventListener('popstate', handleBackPress)
    }
  }, [handleBackPress])
}

useEffect个"观察"handleBackPress个变化,useCallback个"观察"onBackEvent个变化.

所以我的问题是:

  • 这是裁员吗?
  • 如果是这样,我如何简化这段代码呢?

推荐答案

使用‘useEffect’和‘useCallback’是冗余吗?

独自一人,与世隔绝?没关系,您请.这两个挂钩的存在是为了服务于两个完全不同的目的.

  • useEffect

    The useEffect个 hook is to issue intentional side-effects from what is otherwise considered to be a pure function that renders UI from JSX.

  • useCallback

    The useCallback个 hook memoizes a function such that a stable function reference is passed along, e.g. to a useEffect个 hook, or to children as props, so it doesn't trigger unnecessary rerenders. In other words, it is a performance optimization/optimizer.

Instead of recreating the handleBackPress and adding/removing event listeners each time the onBackEvent is changed, I recommend moving handleBackPress into the useEffect个 hook so it can be provided as a stable callback reference, and to use a React ref to cache the onBackEvent callback. Use an empty array for the useEffect个 hook so the listeners are only instantiated once and removed when the component unmounts via the cleanup function.

示例:

export default function useIndex(onBackEvent?: () => void) {
  const onBackEventRef = React.useRef<() => void | undefined>();

  useEffect(() => {
    onBackEventRef.current = onBackEvent;
  }, [onBackEvent]);

  useEffect( () => {
    const handleBackPress = (e: PopStateEvent) => {
      e.preventDefault();
      window.history.pushState(null, '', window.location.pathname);
      if (onBackEventRef.current) {
        onBackEventRef.current();
      }
    };

    window.history.pushState(null, '', window.location.pathname);
    window.addEventListener('popstate', handleBackPress);

    return () => {
      window.removeEventListener('popstate', handleBackPress);
    };
  }, []);
}

Typescript相关问答推荐

无需刷新即可让现场访客逆变

对于使用另一个对象键和值类型的对象使用TS Generics

带有联合参数的静态大小数组

TS不推断类型在条件判断后具有属性'

TypeScript泛型参数抛出错误—?&#"' 39;预期"

如果请求是流,如何等待所有响应块(Axios)

单击并移除for循环中的一项也会影响另一项

具有泛型类方法的类方法修饰符

如何使用函数填充对象?

如何在typescript中设置对象分配时的键类型和值类型

参数属性类型定义的REACT-RUTER-DOM中的加载器属性错误

如何 bootstrap TS编译器为类型化属性`T`推断正确的类型?

我怎样才能正确地输入这个函数,使它在没有提供正确的参数时出错

基于泛型的类型脚本修改类型

是否可以将类型参数约束为不具有属性?

如何使用 runInInjectionContext 中的参数测试功能性路由防护

元组解释

redux-toolkit、createAsyncThunk 错误

如何强制对象数组中的对象属性具有非空字符串值?

当并非所有歧视值都已知时,如何缩小受歧视联盟的范围?