Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooks的依赖项 #170

Open
yaofly2012 opened this issue Sep 21, 2020 · 0 comments
Open

Hooks的依赖项 #170

yaofly2012 opened this issue Sep 21, 2020 · 0 comments

Comments

@yaofly2012
Copy link
Owner

yaofly2012 commented Sep 21, 2020

Hooks useEffect/useLayoutEffect/useMemo/useCallback都具有依赖项,可以进行有条件执行callback。

一、依赖项

1.1 什么是有效的依赖项 ?

gaearon提到

This is expected. Dependencies should only include values that participate in top-down React data flow. Such as props, state, and what you calculate from them. Ref containers are fine too (since they can be passed down).

However, it doesn’t make sense to add ref.current as a dependency. For the same reason it doesn’t make sense to add window.myVariable. When it updates, React won’t know about it, and won’t update your component.

  1. stateprops或则它们的计算值;
  • 作为propsref也可以作为deps
  • 原因后面会提到。
  1. 其他(ref.current, 全局变量等)都不可以作为deps
    原因后面会提到。

1.2 哪些变量应该放入依赖项数组?

如果state, props或则它们的计算值作为useEffect/useLayoutEffect/useMemo/useCallback实参函数或则在实参函数里被访问到,则需要放入依赖项数组。

这里需要注意的是实参函数如果来自state或者props也要写入依赖数组。

function Demo({ func }) {
  useEffect(func, [])
  return null;
}

React Hook useEffect has a missing dependency: 'func'. Either include it or remove the dependency array

不过感觉没必要啊???关于此事这里Pass a dependency array to a custom hook?还进行了讨论。
总结下来就是没必要,有些第三方库(比如use-deep-compare-effect)也没有这样做。

1.3 ref.current可以作为依赖数项吗?

上面提到ref.current是不可以作为依赖项的,因为ref.current的变化是不会被跟踪的(即不会触发re-render)。

function Demo({ func }) {
  const changedRef = useRef(0);
  useEffect(() => {
    func()
  }, [func, changedRef.current])
  return null;
}

React Hook useEffect has an unnecessary dependency: 'changedRef.current'. Either exclude it or remove the dependency array. Mutable values like 'changedRef.current' aren't valid dependencies because mutating them
doesn't re-render the component react-hooks/exhaustive-deps

但是这样写又不报错:

function Demo({ func }) {
  const changedRef = useRef(0);
  useEffect(func, [func, changedRef.current])
  return null;
}

原因不知~~~想必eslint-plugin-react-hooks很聪明,当发现changedRef.current是否作为依赖项都无所谓时就不报错了。
总之:不要把ref.current作为依赖项,除非必须这样做,并且你知道这没问题

1.4 ref.current作为依赖数项 !

这是要打脸吗?上面明明在强调不要把ref.current作为依赖项。总有些场景需要吧。
use-deep-compare-effect库就用到了:

function useDeepCompareMemoize(value: DependencyList) {
  const ref = React.useRef<DependencyList>()
  const signalRef = React.useRef<number>(0)

  if (!deepEqual(value, ref.current)) {
    ref.current = value
    signalRef.current += 1
  }

  return [signalRef.current]
}
  1. 功能上没问题;
  2. 需要屏蔽eslint检查// eslint-disable-next-line react-hooks/exhaustive-deps

什么情况下可以把ref.current作为依赖项呢?

ref.current用于缓存state或者props的计算值(即state或者props的变化能引起ref.current变化),此时可以把ref.current作为依赖项。本质上是间接把state或者props的计算值作为依赖项。

二、依赖项什么时候执行?

2.1 什么时候计算依赖项表达式?

依赖项表达式在render阶段计算。可以看看useRef 里的demo。
所以依赖项发生变化得能触发re-render,这也是为啥只有state, props或者它们的计算值才可以作为依赖项的原因。

2.2 怎么比较依赖项的?

每次re-render时逐个比较(Object.is)依赖数组各项和上次缓存的依赖项数组的各元素值。

  1. 每次re-render时依赖数组长度不能变化

The final argument passed to useEffect changed size between renders. The order and size of this array must remain constant.

  1. 因为利用的是Object.is函数比较的,所以对于引用类型的数据比较的是引用。

2.3 深比较依赖项

使用常见比较少吧,如果遇到需要深比较,可以直接把对象的属性作为依赖项。如果真的真的需要深比较可以利用库use-deep-compare-effect

三、Issues/Concern:

  1. useEffect(effect, [ref.current]) is prematurely re-running
  2. Pass a dependency array to a custom hook?
  3. Is it safe to omit functions from the list of dependencies?

参考

  1. 5 Tips to Help You Avoid React Hooks Pitfalls
  2. use-deep-compare-effect
  3. useEffect监听ref报警告和use-deep-compare-effect的实现?
  4. Rules of Hooks
  5. useEffect will unpredictable when depends on ref (useRef)
@yaofly2012 yaofly2012 changed the title hooks(useEffect, useMemo, useCallback)依赖项? hooks(useEffect, useMemo, useCallback)的依赖项 Sep 22, 2020
@yaofly2012 yaofly2012 changed the title hooks(useEffect, useMemo, useCallback)的依赖项 Hooks(useEffect/useLayoutEffect/useMemo/useCallback)的依赖项 Sep 22, 2020
@yaofly2012 yaofly2012 changed the title Hooks(useEffect/useLayoutEffect/useMemo/useCallback)的依赖项 Hooks的依赖项 Nov 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant