React Hooks总结记录

npx

  • 避免安装全局模块
  • 调用项目内部安装的模块

npm run会新建一个shell,并将node_modules加入到系统环境变量,运行完再删除

为什么要有React Hook

  • 组件很难复用状态逻辑
  • 复杂组件难以理解,尤其是生命周期函数
  • React组件一直是函数,使用Hook完全拥抱函数

useState

  • 会触发组件的render
import React, {useState} from 'react'

const LikeButton: React.FC = () => {
    const [like, setLike] = useState(0)
    const [on, setOn] = useState(true)
    return (
        <>
        <button onClick={() => {setLike( like + 1)}}>
            {like}</button>
        <button onClick={() => {setOn(!on)}}>
            {on ? 'on' : 'off'}
        </button>
        </>
    )
}
export default LikeButton;

useEffect

无需清除的Effect

使用useEffect使用DOm完成标题更新

![image.png](https://img-blog.csdnimg.cn/img_convert/2ff615a9940bd158df103421319b26d4.png#align=left&display=inline&height=341&id=MjHBV&margin=[object Object]&name=image.png&originHeight=341&originWidth=685&size=74462&status=done&style=none&width=685)

    // 默认在第一次渲染之后,和每次更新之后都会执行
    useEffect(() => {
        document.title = `点击了${like}`
    })

需要清除的Effect

使用useEffect完成一个鼠标跟踪器
![image.png](https://img-blog.csdnimg.cn/img_convert/fb8ca8e842491c3f40c49a2399c44633.png#align=left&display=inline&height=367&id=gc4x7&margin=[object Object]&name=image.png&originHeight=367&originWidth=836&size=103673&status=done&style=none&width=836)

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

const MouseTracker: React.FC = () => {
    const [positions, setPositions] = useState({x: 0, y: 0})
    useEffect(() => {
        console.log('add effect', positions.x)
        const mouseTracker = (e: MouseEvent) => {
            console.log('inner')
            setPositions({x: e.x, y: e.y})
        }
        document.addEventListener('click', mouseTracker)
        return () => {
            console.log('remove effect', positions.x)
            document.removeEventListener('click', mouseTracker)
        }
    })
    console.log('before render', positions.x)
    return (
        <p>X: {positions.x}, Y: {positions.y}</p>
    )
}

export default MouseTracker

![image.png](https://img-blog.csdnimg.cn/img_convert/1bf20b0f550fbe67f10b11e1c0a12ae8.png#align=left&display=inline&height=203&id=Qng6e&margin=[object Object]&name=image.png&originHeight=203&originWidth=325&size=7006&status=done&style=none&width=325)
add effect总是在before render之后执行

控制useEffect的执行

 useEffect(() => {
        console.log('add effect', positions.x)
        const mouseTracker = (e: MouseEvent) => {
            console.log('inner')
            setPositions({x: e.x, y: e.y})
        }
        document.addEventListener('click', mouseTracker)
        return () => {
            console.log('remove effect', positions.x)
            document.removeEventListener('click', mouseTracker)
        }
    }, [])

这里实际就是componentDidMount和componentWillUnmount

自定义Hook

  • 将组件逻辑提取到可重用的函数中
  • 代码:使用自定义Hook抽象鼠标跟踪器
import React, {useState, useEffect} from 'react'

const useMousePosition = () => {
    const [positions, setPositions] = useState({x: 0, y: 0})
    useEffect(() => {
        console.log('add effect', positions.x)
        const mouseTracker = (e: MouseEvent) => {
            console.log('inner')
            setPositions({x: e.x, y: e.y})
        }
        document.addEventListener('mousemove', mouseTracker)
        return () => {
            console.log('remove effect', positions.x)
            document.removeEventListener('mousemove', mouseTracker)
        }
    }, [])
    return positions;
}
export default useMousePosition

HOC 高阶组件

  • 高阶组件就是一个函数,接受一个组件作为参数,返回一个新的组件
  • 常见实现方法:属性代理和反向继承
  • 劣势:
    • 添加不必要的界面结构,而不是单纯的逻辑
    • 难以理解
    • 想要理解,还需要去找被包裹的组件

使用自定义hook完成useURLLoader

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

const useURLLoader = (url: string, deps: any[] = []) => {
    const [data, setData] = useState<any>(null);
    const [loading, setLoading] = useState(false)
    useEffect(() => {
        setLoading(true)
        axios.get(url).then(res => {
            setData(res.data)
            setLoading(false)
        })
    },deps)
    return [data, loading]
}

export default useURLLoader;

useRef

为了解决什么问题

  • 任意一次渲染中的state值都是常量,不会随着时间改变而变,渲染输出会变,是因为组件被一次次调用,而每一次调用组件渲染时里面的state值独立于其他渲染。
  • 在任意一次渲染中props和state值是始终保持不变的,如果props和state在不同的渲染中是相互独立的,那么使用到他们任何值也是相互独立的。

作用

  • 多次渲染之间的纽带
    1. useRef在所有的render中保持唯一的引用
    2. 需要注意的是对ref值改变不会重新render
import React, {useState, useEffect, useRef} from 'react'

const LikeButton: React.FC = () => {
    const [like, setLike] = useState(0)
    // {current: 0}
    const likeRef = useRef(0)
    // 默认在第一次渲染之后,和每次更新之后都会执行
    useEffect(() => {
        document.title = `点击了${like}`
    })
    function handleAlertClick(){
        setTimeout(() => {
            alert(`点击了 ${likeRef.current}`)
        },3000)
    }
    return (
        <>
            <button onClick={() => {
                setLike(like + 1)
                likeRef.current++;
            }}>
                {like}</button>
            <button onClick={handleAlertClick}>Alert!</button>
        </>
    )
}
export default LikeButton;
  • 模拟componentDidUpdate生命周期
import React, {useState, useEffect, useRef} from 'react'

const LikeButton: React.FC = () => {
 		const didMountRef = useRef(false)
    // 模拟componentDidUpdate
    useEffect(() => {
        if (didMountRef.current) {
            console.log('this is updated')
        } else {
            didMountRef.current = true;
        }
    })
    return (
        <>
    
        </>
    )
}
export default LikeButton;   

  • 访问dom节点
import React, {useState, useEffect, useRef} from 'react'

const LikeButton: React.FC = () => {
    const domRef = useRef<HTMLInputElement>(null)
    // 将input focus
    useEffect(() => {
        if(domRef && domRef.current){
            domRef.current.focus()
        }
    })
  
    return (
        <>
            <input type="text" ref={domRef}/>
        </>
    )
}
export default LikeButton;

useContext

  • 解决多层传递属性

Hook规则

  • 只在最顶层使用hook
  • 只在React函数中调用hook

其他hook

  • useReducer:简化有复杂逻辑的useState
  • useCallback
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值