React Hooks知识点

系列文章目录



前言

React Hooks


一、函数组件特点

  • 没有组件实例
  • 没有生命周期
  • 没有state 和 setState,只能接收 props

二、useState

默认函数组件没有state

函数组件是一个纯函数,执行完即销毁,无法存储state

需要 State Hook,即把state功能“钩”到纯函数中

  • useState(0) 传入初始值,返回数组[state, setState]
  • 通过 state 获取值
  • 通过 setState(1) 修改值
import React,{useState} from 'react';

function ClickFn() {
    // 数组解构
    const [count, setCount] = useState(0);
    
    return <div>
        <p>{count}</p>
        <button onClick={() => setState(count +1)}>点击</button>
    </div>
}

export default ClickFn

三、useEffect

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

function ClickFn() {
    // 数组解构
    const [count, setCount] = useState(0);

    // 模拟 class 组件的DidMount 和 DidUpdate
    useEffect(() => {
        console.log('发起请求')
    })

    // 模拟 class 组件的DidMount
    useEffect(() => {
        console.log('加载完成')
    },[])    // 第二个参数是[] (不依赖于state)

    // 模拟 class 组件的DidUpdate
    useEffect(() => {
        console.log('更新了')
    },[count])    // 第二个参数是依赖的state


    // 模拟 class 组件的willUnMount
    useEffect(() => {
        let timerId = window.setInterval(() => {
            console.log(Date.now())
        },1000);

        // 返回一个函数
        // 模拟willUnMount
        return () => {
            window.clearInterval(timerId)
        }
    },[])

    
    return <div>
        <p>{count}</p>
        <button onClick={() => setState(count +1)}>点击</button>
    </div>
}

export default ClickFn

使用总结

模拟componentDidMount - useEffect 依赖

模拟componentDidUpdate - useEffect 无依赖,或者依赖[a,b]

模拟componentWillUnMount - useEffect 中返回一个函数

注意:模拟WillUnMount,但不完全相等

特别注意

此处并不完全等同于WillUnMount

props发生变化,即更新,也会执行结束监听

准确的说:返回的函数,会在下一次 effect 执行之前,被执行

四、useRef

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

function UseRef() {
    const btnRef = useRef(null); // 初始值
    
    useEffect(() => {
        console.log(btnRef.current); // DOM节点
        // <button>click</button>
    },[]);

    return <div>
        <button ref={btnRef}>click</button>
    </div>
}

export default UseRef

五、useContext

import React,{useContext} from 'react';

const themes = {
    light: {
        foreground: '#000',
        background: '#eee'
    },
    dark: {
        foreground: '#fff',
        background: '#222'        
    }
}

// 创建Context
const ThemeContext = React.createContext(themes.light); // 初始值

function ThemeButton() {
    const theme = useContext(ThemeContext);
    return <button style={{background: theme.background,color:theme.foreground}}>
        hello
    </button>
}

function Toolbar() {
    return <div>
        <ThemeButton></ThemeButton>
    </div>
}

function App() {
    return <ThemeContext.Provider value={themes.dark}>
        <Toolbar></Toolbar>
    </ThemeContext.Provider>
}

export default App;

六、useReducer

import React,{useReducer} from 'react';

const initialState = {count: 0};

const reducer = (state, action) => {
    switch (action.type) {
        case 'increment': 
            return {count: state.count + 1}
        case 'decrement': 
            return {count: state.count - 1}
        default:
            return state
    }
}

function App() {
    // 很像 const [count, setCount] = useState(0)
    const [state, dispaatch] = useReducer(reducer, initialState);

    return <div>
        count: {state.count}
        <button onClick={() => dispatch({ type:'increment' })}>increment</button>
        <button onClick={() => dispatch({ type:'decrement' })}>decrement</button>
    </div>
}

export default App

useReducer 和 redux 的区别

1.useReducer 是 useState 的代替方案,用于 state 复杂变化

2.useReducer 是单个组件状态管理,组件通讯还需要props

3.redux 是全局的状态管理,多组件共享数据

七、useMemo

import React, { useState, memo, useMemo } from 'react';

// 子组件
// memo 类似 class组件 PureComponent,对 props 进行浅层比较
const Child = memo(({userInfo}) => {
    console.log('Child render');
    
    return <div>
        <p>this is child {userInfo.name} {userInfo.age}</p>
    </div>
})

// 父组件
function App() {
    console.log('parent render...');
    
    const [count, setCount] = useState(0);
    const [name, setName] = useState('豆豆');

    // const userInfo = {name, age: 20};
    // 用 useMemo 缓存数据,有依赖
    const userInfo = useMemo(() => {
        return { name, age: 21};
    },[name])
    
    return <div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo}></Child>
    </div>
}

export default App;

useMemo 总结

1.React 默认会更新所有子组件

2.class 组件使用 SCU 和 PureComponent 做优化

3.Hooks 中使用useMemo,但优化原理相同

八、useCallback

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

// 子组件
// memo 类似 class组件 PureComponent,对 props 进行浅层比较
const Child = memo(({userInfo,onChange}) => {
    console.log('Child render');
    
    return <div>
        <p>this is child {userInfo.name} {userInfo.age}</p>
        <input onChange={onChange}></input>
    </div>
})

// 父组件
function App() {
    console.log('parent render...');
    
    const [count, setCount] = useState(0);
    const [name, setName] = useState('豆豆');

    // const userInfo = {name, age: 20};
    // 用 useMemo 缓存数据,有依赖
    const userInfo = useMemo(() => {
        return { name, age: 21};
    },[name]);

    // 用 useCallback 缓存函数
    const onChange = useCallback(e => {
        console.log(e.target.value);
    },[])
    
    return <div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo} onChange={onChange}></Child>
    </div>
}

export default App;

useCallback总结

1.useMemo缓存数据

2.useCallback 缓存函数

3.两者是 React Hooks 的常见优化策略

九、自定义Hook

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

// 封装 axios 发送网络请求的自定义 Hook
function useAxios(url) {
    const [loading, setLoading] = useState(false);
    const [data,setData] = useState();
    const [error, setError] = useState();

    useEffect(() => {
        // 利用 axios 发送网络请求
        setLoading(true);
        axios.get(url) // 发送一个 get 请求
            .then(res => setData(res))
            .catch(err => setError(err))
            .finally(() => setLoading(false))
    },[url])
    
    return [loading, data, error];
}

export default useAxios;
import React from 'react';
import useAxios from 'useAxios';

function App(url) {
    const url='...';
    // 数组解构
    const [loading, data, error] = useAxios(url);
    
    if(loading) return <div>loading...</div>

    return error
        ? <div>{JSON.stringify(error)}</div>
        : <div>{JSON.stringify(data)}</div>
}

export default App;

总结

1.本质是一个函数,以use开头

2.内部正常使用 useState useEffect 或者其他Hooks

3.自定义返回结果,格式不限

十、Hooks使用规范

命名规范 use开头

只能用于React函数组件和自定义Hook中,其他地方不可以

只能用于顶层代码,不能在循环、判断中使用Hooks

eslint 插件 eslint-plugin-hooks 可以帮到你

Hooks 严重依赖于执行顺序

1.函数组件,纯组件,执行完即销毁

2.所以,无论组件初始化(render) 还是组件更新(re-render)

3.都会重新执行一次这个函数,获取最新的组件

4.这一点和 class 组件不一样,class组件初始化实例不会销毁

render: 初始化 state 的值

re-render: 读取 state 的值

render: 添加 effect 函数

re-render: 替换 effect 函数(内部函数也会重新定义)

useHook调用顺序必须保持一致

1.无论是 render 还是 re-render,Hooks调用顺序必须一致

2.如果Hooks出现在循环、判断里,则无法保证顺序一直

3.Hooks严重依赖于调用顺序

十一、class 组件逻辑复用

  • Mixins早已废弃(1.变量作用域来源不清 2.属性重名 3.Mixins引入过多会导致顺序冲突)
  • 高阶组件 HOC(1.组件层级嵌套过多,不易渲染,不易调试 2.HOC会劫持props,必须严格规范)
  • Render Prop(1.学习成本高,不易理解 2.只能传递纯函数,而默认情况下纯函数功能有限)

十二、React Hooks 逻辑复用

  • 完全符合 Hooks 原有规则,没有其他要求,易理解记忆
  • 变量作用域明确
  • 不会产生组件嵌套

十三、React Hooks 注意事项

  • useState 初始化值,只有第一次有效(re-render:只恢复初始化的state值,不会再重新设置新的值,只能用 set 修改)
  • useEffect 内部不能修改 state
    function UseEffectChangeState() {
        const [count, setCount] = useState(0)
    
        // 模拟 DidMount
        useEffect(() => {
            console.log('useEffect-',count);
            
            // 定时任务
            const timer = setInterval(() => {
                console.log('setInterval-',count);
                setCount(count + 1);
            },1000)
    
            // 清除定时任务
            return () => clearTimeout(timer)
        },[]) // 依赖是[]
    
        // 依赖为 [] 时(didMount):re-render 不会重新执行 effect 函数
        // 没有依赖(didMount/didUpdate): re-render 会重新执行 effect 函数
    
        return <div>count: {count} </div>
    }
  • useEffect 可能出现死循环(依赖里有{ } [ ] 引用类型)

总结

React Hooks相关知识点

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值