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>
)
}
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;