第一课: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}/>
相关推荐
thatway19896 小时前
闲聊-关于AI终结者的警醒
前端
努力的小郑6 小时前
突发!Claude Code 51万行源码全网裸奔:一场史诗级“开源”事故,国内大厂笑麻了
前端·后端·ai编程
七度黑光6 小时前
用 openclaw 给故障复盘打分:质量审核自动化实践
运维·服务器·前端·数据库·自动化
HashTang6 小时前
Claude Code 源码中 REPL.tsx 深度解析:一个 5005 行 React 组件的架构启示
前端·后端·ai编程
wendycwb7 小时前
前端城市地址根据最后一级倒推,获取各层级id的方法
前端·vue.js·typescript
终端鹿8 小时前
Vue3 模板引用 (ref):操作 DOM 与子组件实例 从入门到精通
前端·javascript·vue.js
千寻girling8 小时前
不知道 Java 全栈 + AI 编程有没有搞头 ?
前端·人工智能·后端
小码哥_常8 小时前
Android开发:精准捕获应用的前后台行踪
前端
蜡台8 小时前
Vue 打包优化
前端·javascript·vue.js·vite·vue-cli
木斯佳9 小时前
前端八股文面经大全:快手前端一面 (2026-03-29)·面经深度解析
前端·宏任务·原型链·闭包