react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )

简介: react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )

Hook 是什么?

React 中,以“use”开头的函数都被称为 Hook。

Hook 是实现特殊功能的函数,只在 React 渲染时有效,只能在组件或自定义 Hook 的最顶层调用。

React 内置了很多 Hook ,你也可以自定义 Hook。

Hook 的使用规范

1.只能在 react 函数组件和自定义 Hook 中使用

2.只能在顶层使用,不能在判断(如 if 语句)/ 循环(如 for 语句)中使用

因为 Hooks 严重依赖于调用顺序,在组件挂载(render)和更新(re-render)时,Hooks 的调用顺序必须保持一致,若在判断/循环语句中使用,则可能引发 Hooks 的调用顺序发生改变,导致 Hooks 内的逻辑错乱(如响应式变量的值赋值给了其他变量)。

Hook 实现组件逻辑复用的好处

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

其他方式实现组件逻辑复用的缺陷

Mixins(已废弃)的缺陷

与 vue 相同

  • 变量作用域来源不清
  • 属性重名
  • Mixins 引入过多会导致顺序冲突

高阶组件 HOC 的缺陷

高阶组件 HOC 是 react 的 class 组件实现组件逻辑复用的一种方式

  • 组件层级嵌套过多,不易渲染,不易调试
  • HOC 会劫持 props,必须严格规范,容易出现疏漏

Render Prop 的缺陷

Render Prop 是 react 的 class 组件实现组件逻辑复用的另一种方式

  • 学习成本高,不易理解
  • 只能传递纯函数,而默认情况下纯函数功能有限

React 的内置 Hook

useState

详见 https://blog.csdn.net/weixin_41192489/article/details/138664118


useReducer

详见 https://blog.csdn.net/weixin_41192489/article/details/138863860


useRef

详见 https://blog.csdn.net/weixin_41192489/article/details/138952934


useEffect

详见 https://blog.csdn.net/weixin_41192489/article/details/138706946


useContext

详见 https://blog.csdn.net/weixin_41192489/article/details/138700487


useMemo

详见 https://blog.csdn.net/weixin_41192489/article/details/138909376


useCallback

详见 https://blog.csdn.net/weixin_41192489/article/details/138911123

自定义 Hook

即根据自己的业务需要编写use开头的函数,实现逻辑封装和复用。

自定义 Hook 的步骤

  1. 新建文件 myHooks.js,存放所有自定义的 hook
  2. 将可复用的逻辑封装成use开头的函数,以对象或数组的数据格式 return 组件中需要用到的变量和函数
  3. 对外导出自定义的 hook
  4. 在目标组件中导入自定义的 hook
  5. 通过对象/数组解构赋值(与自定义 hook 中return 的数据格式对应),使用自定义的 hook

范例1 - 切换显示隐藏 useToggle

myHooks.js

import { useState } from "react";

// 切换显示隐藏
export const useToggle = (initValue) => {
  const [show, setShow] = useState(initValue);

  function toggleShow() {
    setShow(!show);
  }

  return [show, toggleShow];
};

index.jsx

import { useToggle } from "./myHooks.js";

function Demo() {
  const [showTitle, toggleShowTitle] = useToggle(true);
  const [showContent, toggleShowContent] = useToggle(false);

  return (
    <>
      {showTitle && <h1>标题</h1>}
      <button onClick={toggleShowTitle}>显示/隐藏标题</button>

      <div>
        {showContent && <p>段落</p>}
        <button onClick={toggleShowContent}>显示/隐藏内容</button>
      </div>
    </>
  );
}

export default Demo;

范例2 - 组件挂载时请求接口数据 useGetInitData

myHooks.js

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

// 访问接口
export const useGetInitData = (url) => {
  const [data, setData] = useState([]);
  useEffect(() => {
    async function getData() {
      const res = await axios.get(url);
      setData(res.data);
    }
    getData();
  }, []);

  return [data, setData];
};

index.jsx

import { useGetInitData } from "./myHooks.js";

function Demo() {
  const [list, setList] = useGetInitData("http://localhost:3000/dataList");

  function clearList() {
    setList([]);
  }

  return (
    <>
      {list.map((item) => (
        <div key={item.id}>{item.title}</div>
      ))}
      <button onClick={clearList}>清空</button>
    </>
  );
}

export default Demo;

范例3 - url 改变时请求接口数据 useAxios

useAxios.js

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 useAxios from './useAxios'
 
 const url = 'http://localhost:3000/'
 // 数组解构
 const [loading, data, error] = useAxios(url)

 if (loading) return <div>loading...</div>

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

范例4 - 实时获取鼠标坐标 useAxios

useMousePosition.js

import { useState, useEffect } from 'react'

function useMousePosition() {
    const [x, setX] = useState(0)
    const [y, setY] = useState(0)

    useEffect(() => {
        function mouseMoveHandler(event) {
            setX(event.clientX)
            setY(event.clientY)
        }

        // 绑定事件
        document.body.addEventListener('mousemove', mouseMoveHandler)

        // 解绑事件
        return () => document.body.removeEventListener('mousemove', mouseMoveHandler)
    }, [])

    return [x, y]
}

export default useMousePosition

使用

import useMousePosition from './useMousePosition'
 
const [x, y] = useMousePosition()
return <div>
    <p>鼠标位置 {x} {y}</p>
</div>

目录
相关文章
|
19天前
|
前端开发 JavaScript
深入理解并实践React Hooks —— useEffect与useState
深入理解并实践React Hooks —— useEffect与useState
84 1
|
2月前
|
前端开发
react中 useContext 和useReducer的使用
react中 useContext 和useReducer的使用
react中 useContext 和useReducer的使用
|
9天前
|
前端开发
React中函数式Hooks之useEffect的使用
本文通过示例代码讲解了React中`useEffect` Hook的用法,包括模拟生命周期、监听状态和清理资源。
23 2
React中函数式Hooks之useEffect的使用
|
15天前
|
Web App开发 前端开发 测试技术
react18基础教程系列--安装环境及packagejson文件分析
react18基础教程系列--安装环境及packagejson文件分析
|
2月前
|
前端开发 JavaScript
介绍React中的useEffect
【8月更文挑战第6天】介绍React中的useEffect
30 2
|
3月前
|
存储 前端开发 API
useEffect问题之React提供了什么来帮助确保useEffect的依赖被正确指定
useEffect问题之React提供了什么来帮助确保useEffect的依赖被正确指定
|
2月前
|
前端开发 JavaScript UED
React 基础与实践 | 青训营笔记
React 基础与实践 | 青训营笔记
44 0
|
3月前
|
前端开发 JavaScript Java
React 速通笔记
【7月更文挑战第17天】
38 1
|
前端开发
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
71 0
|
前端开发
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之8
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之7
48 0