检查函数是否是由useCallback创建的?

问题描述 投票:0回答:3

我有接受函数作为参数的钩子。如果函数发生不必要的更改,则可能会导致额外的重新渲染。我想确保函数用

useCallback
包装。

即这是一个简化版本:

function useApi({ onSuccess }) {
  if (process.env.NODE_ENV !== 'production' && !isUseCallback(onSuccess)) {
    throw new Error();
  }

  useEffect(() => {
    fetch(...)
      .then(res => res.json())
      .then(onSuccess);
  }, [onSuccess]);
}

如果

onSuccess
发生不必要的更改,那么它将不必要地调用API。可以有
isUseCallback
这个功能吗?我想我必须编写一个自定义的
useCallback
来包装 React 的
useCallback

javascript reactjs react-hooks
3个回答
1
投票

您可以将回调包装在

useRef()
中,以确保
useEffect()
回调引用最新的
onSuccess
:

function useApi({ onSuccess }) {
  const ref = useRef();

  ref.current = onSuccess;

  useEffect(() => {
    fetch(...)
      .then(res => res.json())
      .then(val => ref.current(val));
  }, []);
}

重要的是,您应编写

.then(val => ref.current(val))
而不是仅编写
.then(ref.current)
,以便在
ref.current
解析之前不会发生属性访问
fetch()
。这样
ref.current
等于最近传递给
onSuccess
useApi()


1
投票

我使用 Typescript 解决了这个问题:

/** So we can require arguments passed to our custom hooks to be wrapped in a useCallback().*/
declare function useCallback<T extends (...args: any[]) => any>(
  callback: T,
  deps: ReadonlyArray<any>
): UseCallback<T>

declare module 'react' {
  /** Doesn't exist after compilation. Only exists in TypeScript. */
  export const UseCallbackSymbol: unique symbol

  /** So we can require arguments passed to our custom hooks to be wrapped in a React `useCallback()`.*/
  export type UseCallback<T extends (...args: any[]) => any> = T & {
    [UseCallbackSymbol]: true
  }

  // Override the useCallback function
  export function useCallback<T extends (...args: any[]) => any>(
    callback: T,
    deps: ReadonlyArray<any>
  ): UseCallback<T>
}

.

function useApi(onSuccess: UseCallback<() => any>): any;

useApi(() => {}); // Error
useApi(useCallback(() => {})); // No error

0
投票

您可以使用 npm 包

useCallback
中的
rely-use-callback
代替原始 useCallback。 该包包含
RelyCallback
类型,可用于类型检查

例如:

import { useCallback, RelyCallback } from 'rely-use-callback';

const handleClick = useCallback(() => {}, []);
...

const useSomethinkToDoOnEffect = (  
   todoFunction: RelyCallback<() => void>
) => {  
    useEffect(() => {  
        todoFunction()  
    }, [ todoFunction ]);  
}

const MemoizedComponent:FC<{  
   onClick: RelyCallback<() => void>
}> = memo(() => <ChildComponent onClick={onClick} />)

有关动机的更多信息,您可以阅读https://github.com/vkruglikov/rely-use-callback#-motivation

© www.soinside.com 2019 - 2024. All rights reserved.