react-hooks

react-hooks

使得 function 组件具有 class 组件同等的”特效”(state, 生命周期函数…);

函数式开发;

useState

import React, {useState} from 'react';

function UseState() {
// 初始默认值,未设置时初始化为 undefined
// key1
const [name] = useState("tadm");
const [count, setCount] = useState(0);

return <div>
<p>This is useState by {name}</p>
<p>You clicked {count} times</p>
// key2
<button onClick={()=>{ setCount(count+1) }}>click me</button>
</div>
}
export default UseState;

useEffect

替代生命周期函数:componentDidMount componentDidUpdate componentWillUnmount

可进行副作用操作(网络请求等)

import React, {useState,useEffect} from 'react';

function UseEffect() {
const [name] = useState("tadm");
const [count,setCount] = useState(0);

// key 注意:此方法为异步函数
useEffect(()=>{
console.log(`useEffect=>You clicked ${count} times`)
// const id = setInterval(() => {
// setCount(count + 1);
// }, 1000);
return ()=>{
console.log("unmount");
// 组件卸载前需要清掉定时器
// clearInterval(id);
}
// 传空数组 [] 时,当组件将被销毁时才重新执行
// 传 count,即依赖 count 值,每次 count 发生变化都重新执行
},[count]);

return <div>
<p>This is useEffect by {name}</p>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>
</div>
}

export default UseEffect;

useLayoutEffect

类似 ·useEffect·,不过 useEffect 是渲染后更新数据,不阻塞 DOM 更新;

useLayoutEffect 则会在内容更新到 DOM 上前运行,会阻塞 DOM 更新;

import React, {useEffect, useLayoutEffect, useState} from 'react';

function UseLayoutEffect(props) {
const [count, setCount] = useState(1);

// 点击按钮时 count --> 0,会调用 useLayoutEffect,重新赋值 count 一个随机数值,此时 count 又变化了则又会调用 useLayoutEffect 对 count 进行赋值一个随机数,但是会阻塞 DOM 更新,这样就看不见使用 useEffect 时发生的闪烁现象
useLayoutEffect(()=>{
console.log("dosth")
if(count === 0){
setCount(Math.random() * 100)
}
},[count]);

return (
<div>
<h2>当前数字:{count}</h2>
<button onClick={e => setCount(0)}>click</button>
</div>
);
}

export default UseLayoutEffect;

useContext

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

// key1
const countContext = createContext();

function Counter(){
// 使得父传子更简单
// key2
const obj = useContext(countContext);
return (<h3>{obj.name} --- {obj.count}</h3>);
}

function UseContext() {
const [name] = useState("tadm");
const [count,setCount] = useState(0);

return <div>
<p>This is UseContext by {name}</p>
<p>You clicked {count} times</p>
<button onClick={()=>{setCount(count+1)}}>click me</button>

// key3
<countContext.Provider value={{name,count}}>
<Counter/>
</countContext.Provider>
</div>
}

export default UseContext;

其实也可以直接传入 props,个人感觉更方便。

useReducer & useMemo

useReducer — 替换 useState 来处理逻辑复杂操作;

useMemo — 性能优化(依赖项变化时才进行重新计算 — 缓存值

import React, {useReducer,useEffect,useMemo} from "react";

// key1
const reducer = (state, action) => {
switch (action) {
case 'change':
return state = "tadm1"
case 'add':
return state + 1
case 'sub':
return state - 1
default:
return state
}
}

function UseReducer() {
// key2 (reducer, defaultValue, function) 第三个设置惰性初始化
const [name, dispatch1] = useReducer(reducer, "tadm", undefined);
const [count, dispatch2] = useReducer(reducer, 0, undefined);

function getName() {
console.log('getName触发')
return name
}

useEffect(() => {
console.log('name effect 触发')
}, [name])

useEffect(() => {
console.log('count effect 触发')
}, [count])

// key3 --- memo 化的 name 属性
const memo_name = useMemo(() => {
console.log('name memo 触发')
return name + "---memo"
}, [name])

return (
<div>
<h2>The name is {getName()}</h2>
<h2>memo name {memo_name}</h2>
<h2>The count is {count}</h2>
// key4
// click triggle getName, memo_name
<button onClick={() => dispatch1('change')}>change</button>
// click only triggle getName not triggle useMemo()
<button onClick={() => dispatch2('add')}>Increment</button>
<button onClick={() => dispatch2('sub')}>Decrement</button>
</div>
)
}

export default UseReducer;

useCallback

useMemo类似,只是返回的是缓存的函数

import React, {memo, useState, useCallback, useEffect} from 'react';

function UseCallback() {
const [count, setCount] = useState(1);
const [val, setVal] = useState('');

const callback = useCallback(() => {
console.log("do useCallback")
return count;
}, [count]);

return <div>
<h4> {count}</h4>
<h4> {val}</h4>
<Child callback={callback}/>
<div>
<button onClick={() => setCount(count + 1)}> +</button>
<input value={val} onChange={event => setVal(event.target.value)}/>
</div>
</div>;
}

const Child = memo(({callback}) => {
const [count, setCount] = useState(() => callback());

useEffect(() => {
setCount(callback());
}, [callback]);

return <div> {count}</div>
})

export default UseCallback;

useRef

获取 DOM 对象;

获取上一次状态值;

import React, {useState, useEffect, useMemo, useRef} from 'react';

function UseRef(props) {
const [count, setCount] = useState(0);

const doubleCount = useMemo(() => {
return 2 * count;
}, [count]);

const counterRef = useRef();

useEffect(() => {
// 获取 DOM 对象
// console.log(counterRef.current);
// 获取上一次状态值
counterRef.current = count;
}, [count]);

return (
<>
<div>上一次的值:{counterRef.current}</div>
<button ref={counterRef} onClick={() => {
setCount(count + 1)
}}>Count: {count}, double: {doubleCount}</button>
</>
);
}

export default UseRef;
Author: 𝓣𝓪𝓭𝓶
Link: https://liuhongwei3.github.io/2020/09/18/react-hooks/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.