十分钟让你彻底弄懂React Hooks

137 阅读2分钟

1.换个角度看hook

  • 在使用hook之前,我们先看一条式子

      2x + 1 = y    
    

其中,x是自变量,y是因变量,我们可以从这个角度去理解react hooks,为什么要从这个角度去理解,让我慢慢解析

自变量Hook:useState,useReducer,useContext

因变量Hook:useEffect,useMemo,useCallBack

其他: useRef

2. useState

import React, { useState } from "react";

// useState用来存储一个响应的初始值,setX用于改变这个值
const UseTest = (props) => {
  const [x, setX] = useState(0);
  return (
    <>
      <ul onClick={() => setX(x + 1)}>
        <li>{x}</li>
      </ul>
    </>
  );
};

3. useMemo

useMemo用来缓存一个没有副作用的因变量的值,同时可搭配memo用于性能优化,可以优化自身或者子组件(搭配memo)

const y = useMemo(() => x * 2 + 1, [x]);

4.useCallback

useMemo用来缓存一个没有副作用的因变量的函数,同时可搭配memo用于性能优化,比如我们写一个函数去设置x

const changeX = () => setX(x + 1);

使用后

const changeX = useCallback(() => setX(x + 1));

5. useEffect

当我们使用hook有副作用时,比如请求数据,操作dom,这个时候就需要用到useEffect.

 // 依赖于x,x变化改变标题
  useEffect(() => {
    document.title = x;
  }, [x]);

你可能会想,为啥函数会有副作用,这就引入一个纯函数的概念,固定的输入会有固定的输出

function demo(x) {
    return 2x;
}

// 下面的情况z是随机生成的,所以不会有固定的输出,像请求数据都是异步的

function demo(x) {
    const  z = Math.random();
    return 2x  + z;
}

6.useLayoutEffect

useLayoutEffect看起来和useEffect非常的相似,事实上他们也只有一点区别而已:

  • useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新;
  • useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新;

如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect。

我们来看下面的一段代码:

  • 这段代码在开发中会发生闪烁的现象;
  • 因为我们先将count设置为了0,那么DOM会被更新,并且会执行一次useEffect中的回调函数;
  • 在useEffect中我们发现count为0,又执行一次setCount操作,那么DOM会再次被更新,并且useEffect又会被执行一次;
import React, { useEffect, useState, useLayoutEffect } from 'react';
export default function EffectHookDemo() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count === 0) {
      setCount(Math.random()*200)
    }
  }, [count]);
  
  // 使用下面的layouteffect不会闪烁
  useLayoutEffect(() => {
    if (count === 0) {
      setCount(Math.random()*200)
    }
  }, [count]);
  return (
    <div>
      <h2>当前数字: {count}</h2>
      <button onClick={e => setCount(0)}>随机数</button>
    </div>
  )
}

image.png

7.useContext

当我们需要跨组件通信时,就需要用到useContext

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

const MyContext = createContext();

const GrandSon = () => {
  const count = useContext(MyContext);
  const name = useContext(MyContext);
  console.log(name);
  return (
    <>
      <h1>grandson---{count}</h1>
    </>
  );
};
const Child = (props) => {
  const { count } = props;
  return (
    <>
      <h1>我是子组件{count}</h1>
      <GrandSon />
    </>
  );
};
const useContextDemo = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <MyContext.Provider value={count}>
        <h1>use context {count}</h1>

        <button onClick={() => setCount(count + 1)}>change count</button>
        <Child count={count} />
      </MyContext.Provider>
    </>
  );
};

export default useContextDemo;