Hooks API

作者: 一瓣山河 | 来源:发表于2019-07-28 11:42 被阅读0次

useEffect

// deps 是依赖数组,可以为空 
useEffect(() => {
  console.log('useEffect')
},  [deps]);

useEffect的使用 参考上篇文章

执行时机:

  • useEffect可以看做componentDidMount、componentDidUpdate、componentWillUnmount生命周期的结合。
  • 只有当deps里的变量发生改变时,才会执行。当第二参数是空数组,该effect 只会在组件didMount和willUnmount后执行;当第二个参数为空时,组件每次渲染都会执行。

useMemo

// 返回一个有记忆的值(memoized)
const memoizedValue = useMemo(() => computeExpensiveValue(deps),deps);

// useMemo 可以帮助避免子组件的不必要的rerender

function Parent({ a, b }) {
  // Only re-rendered if `a` changes:
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // Only re-rendered if `b` changes:
  const child2 = useMemo(() => <Child2 b={b} />, [b]);
  return (
    <div>
      {child1}
      {child2}
    </div>
  )
}

执行时机:

  • useMemo组件rendering 的时候执行,在useEffect之前。因此副作用应放在useEffect里,而不是useMemo。
  • 只有当deps发生变化时,useMemo 才会重新计算memoizedValue, 避免渲染时不必要的计算。当第二个参数为空时,组件每次渲染都会执行。

useCallback

// 返回一个有记忆的callback
const memoizedCallback = useCallback(
  () => {
    doSomething(deps);
  },
  [deps],
);

执行时机:

  • 只有当deps发生变化时,memoizedCallback才会改变。这对通过传递callbacks来优化子组件的渲染很有帮助。(配合子组件的shouldComponentUpdate 或者 React.memo 起到减少不必要的渲染的作用)
// useCallback 与useMemo
useCallback(fn, deps) is equivalent to useMemo(() => fn, deps).

useCallback 的真正目的还是在于缓存了每次渲染时 inline callback 的实例,这样方便配合子组件的 shouldComponentUpdate 或者 React.memo 起到减少不必要的渲染的作用。

useCallback 适用于所有的场景吗?
我们知道useCallback也是有依赖项的,如果一个 callback 依赖于一个经常变化的 state,这个 callback 的引用是无法缓存的。React 文档的 FAQ 里也提到了这个问题,还原一下问题的场景:

function Form() {
  const [text, setText] = useState('');

  const handleSubmit = useCallback(() => {
    console.log(text);
  }, [text]); // 每次 text 变化时 handleSubmit 都会变

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <ExpensiveTree onSubmit={handleSubmit} /> // 很重的组件
    </div>
  );
}

官网提出,如果要记忆化的callback函数是一个事件处理器,rendering时不需要调用,那么,你可以用useRef创建一个实例变量,手动把最新的值存进来。例如:

function Form() {
  const [text, updateText] = useState('');
  const textRef = useRef();

  useEffect(() => {
    textRef.current = text; // Write it to the ref
  });

  const handleSubmit = useCallback(() => {
    const currentText = textRef.current; // Read it from the ref
    alert(currentText);
  }, [textRef]); // Don't recreate handleSubmit like [text] would do

  return (
    <div>
      <input value={text} onChange={e => updateText(e.target.value)} />
      <ExpensiveTree onSubmit={handleSubmit} />
    </div>
  );
}

但是,上面的额解决方案也有缺陷,只有在 DOM 更新时才对 ref.current 做更新,会导致在 render 阶段不能调用这个函数。更严重的是,因为对 ref 做了修改,在未来的 React 异步模式下可能会有诡异的情况出现(因此上文中官方的解法也是”异步模式不安全“的)。

怎么避免深度传递callback?

考虑到上面提到的弊端,目前推荐的解决方案是使用useReducer,传递dispatch通过context。reducer 其实是在下次 render 时才执行的,所以在 reducer 里,访问到的永远是新的 props 和 state。

const TodosDispatch = React.createContext(null);

function TodosApp() {
  // useReducer 返回的 dispatch 函数是自带 memoize 的
  // Note: `dispatch` won't change between re-renders
  const [todos, dispatch] = useReducer(todosReducer);

  return (
    <TodosDispatch.Provider value={dispatch}>
      <DeepTree todos={todos} />
    </TodosDispatch.Provider>
  );
}

Any child in the tree inside TodosApp can use the dispatch function to pass actions up to TodosApp:

function DeepChild(props) {
  // If we want to perform an action, we can get dispatch from context.
  const dispatch = useContext(TodosDispatch);

  function handleClick() {
    dispatch({ type: 'add', text: 'hello' });
  }

  return (
    <button onClick={handleClick}>Add todo</button>
  );
}

TodosApp的任何一个子组件都可以使用dispatch函数向TodosApp传递actions.

如果你想同时把 state 作为 context 传递下去,请分成两个 context 来声明。

相关文章

  • React Hooks 入门

    目录 什么是 React Hooks? 为什么要创造 Hooks? Hooks API 一览 Hooks 使用规则...

  • react hooks 学习记录

    Hooks Api 索引 基础 Api useStateuseEffectuseContext返回一个 state...

  • Hooks API

    useEffect useEffect的使用 参考上篇文章 执行时机: useEffect可以看做componen...

  • React Hooks 入门

    React Hooks 是 React v16.8 版本引入了全新的 API。 React Hooks 基本概念 ...

  • 剖析React Hooks底层源码

    Hooks API 类型 据官方声明,hooks 是完全向后兼容的,class componet 不会被移除,作为...

  • react-hooks

    react-hooks react-hooks 是react16.8以后,react新增的钩子API,目的是增加代...

  • React Hooks API

    1. useState 等价于 复杂的state 注意:useState只能放在函数组件内部,不能单独拿出来 2....

  • 【React】Hooks API

    参考链接【https://reactjs.org/docs/hooks-intro.html】【https://m...

  • 💚一个简单愉悦的 hooks 使用库 react-hooks-e

    react-hooks-easy 封装了每种变量类型统一的增删改查API,为hooks 增加订阅模式,方便组件通信...

  • 如何编写自定义webpack plugin?

    参考文章:https://webpack.docschina.org/api/compiler-hooks/[ht...

网友评论

      本文标题:Hooks API

      本文链接:https://www.haomeiwen.com/subject/jnmqrctx.html