第一课:React的Hooks

npx是什么?

  • 避免安全全局模块

Hook规则

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

定义函数组件

javascript 复制代码
interface IHelloProps {
    message?: string
}

// const Hello = (props: IHelloProps) => {
//     return (
//         <div>
//             <h1>{props.message}</h1>
//         </div>
//     )
// }

const Hello: React.FC<IHelloProps> = (props) => {
    return (
        <div>
            <h1>{props.message}</h1>
        </div>
    )
}

export default Hello

hook的学习

老的hook

  • componetDidMount()
  • componetDidUpdate()
  • componetUnMonunt()
    新的Hook完全拥抱函数。

State Hook

在函数组件内部使用hook

  • 改变组件状态,组件里面记住状态的值。
javascript 复制代码
import React, {useState} from "react";
const LikeButton: React.FC = () => {
    const [obj, setObj] = useState({like: 0, on: true})
    return (
        <>
            <button onClick={() => setObj({like: obj.like + 1, on: obj.on})}>
                {obj.like}👍
            </button>
            <button onClick={() => setObj({like: obj.like, on: !obj.on})}>
                {obj.on ? 'ON' : 'OFF'}
            </button>
        </>
    )
}
export default LikeButton

Effect Hook

  • 无需清除的Effect
  • 使用useEffect完成标题的更新
  • 在老的class 中使用DiaMount 和 DidUpdate两个方法里面执行。

useEffect 在每次dom模型渲染之后,都会执行触发。

javascript 复制代码
    useEffect(() => {
        document.title = `点击了${obj.like}次`
    });
需要清除的Effect

注册的dom事件,要及时清除,否则会在组件每次渲染的时候,都会注册一次。

javascript 复制代码
import {useEffect, useState} from "react";


const MouseTracker: React.FC = () => {
    const [positions, setPositions] = useState({x: 0, y: 0})

    useEffect(() => {
        console.log('add effect:', positions.x)
        const updateMouse = (e: MouseEvent) => {
            console.log("inner")
            setPositions({x: e.clientX, y: e.clientY})
        }
        document.addEventListener('click', updateMouse)

        return () => {
            console.log('remove effect:', positions.x)
            document.removeEventListener('click', updateMouse)
        }
    });
    console.log('before render', positions.x)
    return (
        <p>鼠标位置:{positions.x}, {positions.y}</p>
    )
}

export default MouseTracker;
控制useEffect 的执行

可以使用最后一个参数数组[], 控制useEffect的执行时机,只有这些值发生变化,才会重新执行一次useEffect()

javascript 复制代码
    useEffect(() => {
        console.log('add button effect:', obj.like)
        document.title = `点击了${obj.like}次`
    }, [obj.like, on]);

自定义Hook

自定义hooks,必须以use开头。然后可以在多个组件中引入,互不干扰。

javascript 复制代码
import {useEffect, useState} from "react";

const useMousePosition = () => {
    const [positions, setPositions] = useState({x: 0, y: 0})

    useEffect(() => {
        console.log('add use effect:', positions.x)
        const updateMouse = (e: MouseEvent) => {
            console.log("use inner")
            setPositions({x: e.clientX, y: e.clientY})
        }
        document.addEventListener('mousemove', updateMouse)

        return () => {
            console.log('remove use  effect:', positions.x)
            document.removeEventListener('mousemove', updateMouse)
        }
    }, []);
    return positions
}

export default useMousePosition

在其它组件中使用:

  • 导入
    import useMousePosition from ".../hooks/useMousePosition";
  • 使用里面的值
    const positions = useMousePosition()

HOC 高阶组件(不太好的组件)

  • 可以对已有的组件进行转换成新组件。
  • 本身是一个函数,接收一个函数,返回另一个函数。

自定义hook完成HOC类似功能(更简单)

自定义:useURLLoader 功能。

javascript 复制代码
import axios from 'axios'
import {useEffect, useState} from "react";

const useURLLoader = (url: string, deps: any[] = []) => {

    const [data, setData] = useState<any>(null)
    const [loading, setLoading] = useState<boolean>(false)

    useEffect(() => {
        setLoading(true)
        axios.get(url).then(result => {
            setData(result.data)
            setLoading(false)
        })
    }, deps);
    return [data, loading]
}

export default useURLLoader


interface IShowResult {
    message: string
    status: string
}


通过count 控制组件再次重新请求
const [data, loading] = useURLLoader('https://dog.ceo/api/breeds/image/random', [count])
// data 是any 类型,强制转化成IShowResult
const dogResult = data as IShowResult

useRef(改变ref里面的current值,不会重新渲染dom)

修改Ref不会触发组件的重新渲染。

  • 使用用 ref 引用一个值
  • 通过 ref 操作 DOM
  • 避免重复创建 ref 的内容

特点:

  • 改变 ref.current 属性时,React 不会重新渲染组件。 所以不适合保存期望展示在屏幕上的信息。
  • 可以在 Effect 中读取和写入 ref
  • 可以在事件处理程序中读取和写入 ref
  • 不要在渲染期间写入或者读取 ref.current
javascript 复制代码
    const likeRef = useRef(0)
    - current 泛型的T
    
    function handleAlertClick() {
        setTimeout(() => {
            alert(`点击了${likeRef.current}次`)
        }, 3000)
    }
    
复制代码
useRef 可以模拟操作dom
javascript 复制代码
    const domRef = useRef<HTMLInputElement>(null)
    useEffect(() => {
        if(domRef && domRef.current){
            domRef.current.focus()
        }
    });
    <input type="text" ref={domRef}/>
相关推荐
明月_清风1 天前
小程序云函数:从入门到全栈的“降维打击”指南
前端·微信小程序·小程序·云开发
wuhen_n1 天前
告别 Options API:为什么 Composition API 是逻辑复用的未来?
前端·javascript·vue.js
明月_清风1 天前
前端异常捕获:从“页面崩了”到“精准定位”的实战架构
前端·javascript·监控
wuhen_n1 天前
高效的数据解构:用 toRefs 和 toRef 保持响应性
前端·javascript·vue.js
小兵张健1 天前
价值1000的 AI 工作流:Codex 通用前端协作模式
前端·aigc·ai编程
sunny_1 天前
面试踩大坑!同一段 Node.js 代码,CJS 和 ESM 的执行顺序居然是反的?!99% 的人都答错了
前端·面试·node.js
拉不动的猪1 天前
移动端调试工具VConsole初始化时的加载阻塞问题
前端·javascript·微信小程序
ayqy贾杰1 天前
Agent First Engineering
前端·vue.js·面试
IT_陈寒2 天前
SpringBoot实战:5个让你的API性能翻倍的隐藏技巧
前端·人工智能·后端
iceiceiceice2 天前
iOS PDF阅读器段评实现:如何从 PDFSelection 精准还原一个自然段
前端·人工智能·ios