1. useEffect 执行的是副作用
  2. useEffect 不同的事情分开放,分开声明 useEffect
  3. 不关心生命周期函数,统一在渲染后调用
  4. 第二个参数可选,是数组,在数组每一项都不变得情况下,才不会渲染
    1. 阻止 useEffect再次渲染
    2. 找到依赖的参数,避免重复计算
    3. 第二个参数 useEffect的精髓
    4. useEffect会比较前一次渲染和后一次渲染的值
    5. useEffect的不作为componentDidUnmount的话,传入第二个参数时一定注意
      1. 第二个参数不能为引用类型,数组或对象;引用类型比较不出来数据的变化,会造成死循环
  5. 副作用:都是围绕组件的渲染和重新渲染

    1. 精准控制第二个参数,防止组件或事件重复渲染
    2. useEffect(() => {}, [])
    3. 副作用 https://www.jianshu.com/p/dffa57f8dfcf
    4. 绑定事件
    5. 网络请求
    6. 访问 DOM ```jsx function App () {

    useEffect(() => { // componentDidMount return () => { // componentWillUnmount } })

    let renderCounter = useRef(0) renderCounter.current + 1

    useEffect(() => { if (renderCounter > 1) { // componentDidUpdate // 副作用 } })

useEffect(() => { fetch(‘/api/list’).then() }, [])

useEffect(() => { document.title = count }, [count]) }

  1. - 使用setInterval或者setTimeout的,就简单一点,直接 clearInterval()
  2. - 添加监听事件addEventListener的,在函数中 removeEventListener
  3. - axios请求,取消请求
  4. ```jsx
  5. useEffect(() => {
  6. const source = axios.CancelToken.source();
  7. const fetchData = async () => {
  8. const response = await Axios.get("/users", {
  9. cancelToken: source.token
  10. });
  11. };
  12. fetchData()
  13. return () => {
  14. source.cancel();
  15. };
  16. }, [user.id]);

副作用对应的就是纯函数

class 类组件的副作用

  • 绑定事件
  • 网络请求
  • 访问 DOM
  • state状态的改变
  • 生命周期
  • constructor构造函数等都可以看做是副作用

副作用的时机

副作用 useEffect代替

  1. mount 之后 componentDidMount
  2. update 之后 componentDidUpdate
  3. unmount 之前 componentWillUnmount

useEffect没有参数

  1. useEffect可以执行多个,在一个函数里面可以写多个 useEffect
  2. 没有参数,页面每个事件,例如 onClick,onHover 都会触发 useEffect
  3. 如果在里面 调用 setState会死循环,相当于 componentDidUpdate

    1. function App(props) {
    2. 没有参数,页面每个事件,例如 onClickonHover 都会触发 useEffect
    3. 如果在里面 调用 setState会死循环,相当于 componentDidUpdate
    4. useEffect(() => {
    5. console.log('useEffect')
    6. })
    7. }

useEffect参数是空数组

第二个参数是:空数组,只会执行一次
等价于 componentDidMount

  1. function App(props) {
  2. useEffect(() => {
  3. console.log('useEffect')
  4. }, [])
  5. }

useEffect数组有多个参数

第二个参数是多个值的数组,如果依赖项改变,useEffect就会触发

  1. useEffect(() => {
  2. console.log('useEffect')
  3. }, [id, name])

useEffect执行异步

  1. useEffect 可以执行异步,但是不支持 async & await
  2. useEffect要么返回一个函数,要么什么都不返回
  3. useEffect不支持关键字 async

    1. 因为 async将返回一个 promise,useEffect原本的返回类型,将被 Promise代替
    2. 因为 promise既不是函数,也不是 null所以 ```jsx 正确的用法 useEffect(() => { async function getList() { const res = await fetch(‘api/list/‘ + id) const data = await res.json()

      setState(data) }

    getList() }, [id])

useEffect(() => { const getList = async () => { const res = await fetch(‘api/list/‘ + id) const data = await res.json()

  1. setState(data)

}

getList() }, [id])

正确的用法 async function getList(id) { const res = await fetch(‘api/list/‘ + id) const data = await res.json() setState(data) }

useEffect(() => { getList(id) }, [id])

  1. 错误的异步用法:❌
  2. ```jsx
  3. useEffect( async() => {
  4. const res = await fetch('api/list/' + id)
  5. const data = await res.json()
  6. }, [id])

强制更新值

  1. function Counter() {
  2. const [count, setCount] = useState(0)
  3. const [update, setUpdate] = useState(0)
  4. function forceUpdate () {
  5. setUpdate(update => update + 1)
  6. }
  7. const prevCountRef = useRef()
  8. useEffect(() => {
  9. prevCountRef.current = count
  10. })
  11. const prevCount = prevCountRef.current
  12. return <h1>新值:{count}, before: {prevCount}</h1>
  13. }

useLayoutEffect

  1. 在所有 DOM加载完成,才执行 useLayoutEffect
  2. 通常在 useLayoutEffect里面做 DOM相关操作 ```jsx useLayoutEffect(() => {

}, []) ```

纯函数

pure-function

  1. 给一个函数同样的参数, name这个函数永远发那会同样的值
    1. 给一个固定的输入,就会有一个固定的输出
    2. 函数式编程理念
    3. 给 React组件输入相同的 props参数,渲染的UI永远是一样的
  2. 副作用与纯函数相反,指的是一个函数处理了与返回值无关的事情
    1. 例如:ajax异步请求书
    2. 修改了 DOM
    3. console.log 打印了内容等都是副作用
  3. 输入参数一样,输出结果不一样的情况,就是副作用
    1. 副作用会给系统添加不可控因素
    2. 没有必要去避免副作用,要注意代码的健壮性

二元一次方程就是纯函数

  1. 数学中的函数: y = f(x)
  2. 函数的定义:
    1. 在两个非空集合中,存在一种关系,可以让输入值结合中的每项元素,
    2. 皆对应唯一一项输出值集合中的元素

image.png

圆或椭圆就不是纯函数

image.png