react

react hooks常用Api梳理

2023-02-12  本文已影响0人  Gelakola

1、useEffect

作用:处理函数组件中的副作用,如异步操作、延迟操作等,可以替代Class Component的componentDidMount、componentDidUpdate、componentWillUnmount等生命周期

useEffect(()=>{
 // ...do something
})
useEffect(()=>{
 // ...do something
}, [])
useEffect(()=>{
 console.log(count);
}, [count]) //count更新执行
useEffect(() => {
  const id = setInterval(() => {
    setCount(c => c + 1);
  }, 1000);
  return () => clearInterval(id); // 在组件销毁的时候执行
}, []);

2、useContext

用一个简单的示例来做辅助理解。

import React, { createContext, useContext, useState } from "react";

const initialState = { m: 100, n: 50 }; // 定义初始state
const Store = createContext({}); // 创建Context

export default function App() {
  const [state, setState] = useState(initialState); // 创建state读写接口
  return (
    <Store.Provider value={{ state, setState }}> // value值传递变量。
      <Father></Father>
    </Store.Provider>
  );
}

const Father = (props) => {
  console.log("Father");
  const { state, setState } = useContext(Store); //拿到 名字为Store的上下文的value,用两个变量来接收读写接口
  const addN = () => {
    setState((state) => {
      return { ...state, n: state.n + 1 };
    });
  };
  const addM = () => {
    setState((state) => {
      return { ...state, m: state.m + 1 };
    });
  };
  return (
    <div>
      爸爸组件
      <div>n:{state.n}</div>
      <Child />
      <button onClick={addN}>设置n</button>
      <button onClick={addM}>设置m</button>
    </div>
  );
};
const Child = (props) => {
  console.log("son");
  const { state } = useContext(Store); // 读取state
  return (
    <div>
      儿子组件
      <div>m:{state.m}</div>
    </div>
  );
};

3、useReducer

useState的替代方案,useReducer只是一个小范围内的状态管理工具。在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。

useReducer的使用场景:
1、如果你的state是一个数组或者对象
2、如果你的state变化很复杂,经常一个操作需要修改很多state
3、如果你希望构建自动化测试用例来保证程序的稳定性
4、如果你需要在深层子组件里面去修改一些状态(关于这点我们下篇文章会详细介绍)
5、如果你用应用程序比较大,希望UI和业务能够分开维护

import React, { useReducer, useEffect } from "react";
import ReactDOM from "react-dom";

const initialState = {
  count: 0,
  step: 1
};

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { count, step } = state;

  useEffect(() => {
    const id = setInterval(() => {
      dispatch({ type: "tick" });
    }, 1000);
    return () => clearInterval(id);
  }, [dispatch]);

  return (
    <>
      <h1>{count}</h1>
      <input
        value={step}
        onChange={(e) => {
          dispatch({
            type: "step",
            step: Number(e.target.value)
          });
        }}
      />
    </>
  );
}

function reducer(state, action) {
  const { count, step } = state;
  if (action.type === "tick") {
    return { count: count + step, step };
  } else if (action.type === "step") {
    return { count, step: action.step };
  } else {
    throw new Error();
  }
}

4、useMemo 和 useCallback

useMemo 和 useCallback他们可以用来缓存函数、组件、变量,以避免两次渲染间的重复计算。

为什么使用 useMemo 和 useCallback

使用 memo 通常有三个原因: 1. ✅ 防止不必要的 effect。 2. ❗️防止不必要的 re-render。 3. ❗️防止不必要的重复计算。后两种优化往往被误用,导致出现大量的无效优化或冗余优化。

(1)防止不必要的 effect

当变量直接或者通过依赖链成为 useEffect 的依赖项时,那它可能需要被缓存。这是 useMemo 和 useCallback 最基本的用法。

// useMemo示例
const Component = () => {
  // 在 re-renders 之间缓存 a 的引用
  const a = useMemo(() => ({ test: 1 }), []);

  useEffect(() => {
    // 只有当 a 的值变化时,这里才会被触发
    doSomething();
  }, [a]);

  // the rest of the code
};

// useCallback 示例
const Component = () => {
  // 在 re-renders 之间缓存 fetch 函数
  const fetch = useCallback(() => {
    console.log('fetch some data here');
  }, []);

  useEffect(() => {
    // 仅fetch函数的值被改变时,这里才会被触发
    fetch();
  }, [fetch]);

  // the rest of the code

};
(2)防止不必要的 re-render
const App = () => {
  const [state, setState] = useState(1);

  const onClick = useCallback(() => {
    console.log('Do something on click');
  }, []);

  return (
    // 无论 onClick 是否被缓存,Page 都会 re-render 
    <Page onClick={onClick} />
  );
};

当使用 setState 改变 state 时,App 会 re-render,作为子组件的 Page 也会跟着 re-render。这里 useCallback 是完全无效的,它并不能阻止 Page 的 re-render。

const PageMemoized = React.memo(Page);

const App = () => {
  const [state, setState] = useState(1);

  const onClick = useCallback(() => {
    console.log('Do something on click');
  }, []);

  return (
   // useCallback结合memo一起才能控制子组件无效re-render 
    <PageMemoized onClick={onClick} />
  );
};

注意下面这种情况,由于 value 会随着 App 的 re-render 重新定义,引用值发生变化,导致 PageMemoized 仍然会触发 re-render。

const PageMemoized = memo(({value, onClick}) => {
  console.log(value); // 触发父组件的handleBtn方法时,仍然会打印value值,去掉value是常亮活着是memoized类型数据时,触发handleBtn不会打印value
  return <div onClick={onClick}>value的长度:{value?.length}</div>
});

const App = () => {
  const [state, setState] = useState(1);

  const onClick = useCallback(() => {
    console.log('Do something on click');
  }, []);

  const handleBtn = () => {
    setState(state + 1);
  }

  return (
    <>
    <div onClick={handleBtn}>点击按钮</div>
    <span>{state}</span>
    // PageMemoized还是会re-render,因为value不是一个memoized, 使用useMemo处理useMemo(() => [1, 2, 3], [])后,handleBtn触发时子组件console里不会再打印。
    <PageMemoized onClick={onClick} value={[1, 2, 3]} />
    </>
  );
};

现在可以得出结论,必须同时满足以下两个条件,子组件才不会 re-render: 1. 子组件自身被缓存。 2. 子组件所有的 prop 都是memoized。

(3)防止不必要的重复计算

useMemo 的基本作用是,缓存计算结果,避免在每次渲染时都进行高开销的计算。
实际上,组件渲染才是性能的瓶颈,应该把 useMemo 用在程序里渲染昂贵的组件上,而不是数值计算上。当然,除非这个计算真的很昂贵,比如阶乘计算。
至于为什么不给所有的组件都使用 useMemo,useMemo 是有成本的,它会增加整体程序初始化的耗时,并不适合全局全面使用,它更适合做局部的优化。

function App(props) {
  const start = props.start;
  const list = props.list;
  const fibValue = useMemo(() => fibonacci(start), [start]); // 缓存耗时操作
  // const MemoList = useMemo(() => <List list={list} />, [list]); 

  return (
    <>
      <div>Do some expensive calculation: {fibValue}</div>
      {MemoList}
      <Other />
    </>
  );
}

// 只有列表项改变时组件才会re-render
const MemoList = React.memo(({ list }) => {
  return (
    <ul>
      {list.map(item => (
        <li key={item.id}>{item.content}</li>
      ))}
    </ul>
  );
});

相比React.memo,useMemo在组件内部调用,可以访问组件的props和state,所以它拥有更细粒度的依赖控制。

5、useRef

tips: 欢迎各位指正!
参考:
1.How to useMemo and useCallback: you can remove most of them
2.如何正确使用 useMemo 和 useCallback
3.A Complete Guide to useEffect
4.React Hooks完全上手指南

上一篇 下一篇

猜你喜欢

热点阅读