学习react

模块化

export (导出)

  • 导出用来决定一个模块中哪些内容可以被外部查看
  • 导出分成两种默认导出和命名导出
  • 1、默认导出 export default xxx;
  • 一个模块中只能有一个默认导出
  • 2、命名导出
  • export const x = xxx;

import(导入)

  • 导入用来将外部模块中内容导入到当前模块中
  • 1、导入默认模块 import xxx from "xxx";
  • 导入默认模块时,变量名可以自主指定,无需和模块中的变量名对应
  • 在网页中导入模块时,模块的路径必须写完整(./或../开头,扩展名也得写上)
  • 2、命名导入 import { xxx,xxx} from "xxx"

class 类

  • 类中的所有代码都会在严格模式下执行,严格模式下其中一个特点就是,函数的 this 不在是 window,而是 undefined
  • 在类中方法的 this 不是固定的;以方法形式调用时,this 就是当前的实例;以函数形式调用,this 是 undefined
  • 在开发时,在有些场景下,我们希望方法中的 this 是固定的,不会因调用方式不同而改变
  • 如果遇到上述需求,可以使用箭头函数来定义类中的方法
  • 如果类中的方法是以箭头函数定义的,则方法中的 this 恒为当前实例,不会改变
  • this.xxx = this.xxx.bind(this); // 将 xxx 方法的 this 绑定为当前实例

继承

  • 使用 extends 来继承一个类,继承后就相当于将该类的代码复制到了当前类中
  • 当我们使用继承后,被继承的类就称为父类,继承父类的类称为子类
  • 子类继承父类后,将获得父类中所有的属性和方法,也可以创建同名的属性或方法来对父类进行重写
  • class xxx extends xxx {}
  • 当在子类中重写父类构造函数时,必须在子类构造函数中第一时间调用父类构造函数,否则会报错
  • constructor()
  • 使用 static 开头的属性是静态属性,方法是静态方法
  • 静态方法 this 不是实例对象而是当前的类对象

react

三个 API

React.createElement()

  • 用来创建 React 元素
  • React 元素无法修改

ReactDOM.createRoot()

  • 获取跟元素

  • 用来创建 React 的根容器,容器用来放置 React 元素

root.render()

  • 将元素在根元素中显示

  • 用来将 React 元素渲染到根元素中

  • 根元素中所有的内容都会被删除,被 React 元素所替换

  • 当重复调用 render()时,React 会将两次的渲染结果进行比较

  • 他会确保只修改那些发生变化的元素,对 DOM 做最少的修改

JSX

  • JSX 就是 React.createElement()的语法糖
  • JSX 在执行之前都会被 babel 转换为 js 代码

state

  • state 实际就是一个被 React 管理的变量, 当我们通过 setState()修改变量的值时,会触发组件的自动重新渲染

  • 只有 state 值发生变化时,组件才会重新渲染

  • 当 state 的值是一个对象时,是用新对象替换旧对象

  • 当通过 setState 去修改一个 state 时,并不表示当前的 state,它修改的是组件下一次渲染时 state 值

  • setState()会触发组件的重新渲染,它是异步的,所以当调用 setState()需要用旧 state 的值时,一定要注意有可能出现计算错误的情况,为了避免这种情况,可以通过为 setState()传递回调函数的形式来修改 state

  • 改值

    const newObj = Object.assign(target: {},obj)
    newObj.name = "xxx"
    setUser(newObj)
    
  • setUser({...user,name: "xxx"})

useRef() 获取原生 dom 对象

  • 慎用
  • 1、创建一个存储 DOM 对象的容器 使用 useRef()钩子函数
  • const xxx = useRef() // 创建一个容器

  • 钩子函数的注意事项:

  • (1)、React 中的钩子函数只能用于函数组件或自定义钩子

  • (2)、钩子函数只能直接在函数组件中调用

  • 2、将容器设置为想要获取 DOM 对象元素的 ref 属性

  • <div ref={xxx}></div>

  • useRef() 返回的就是一个普通的 js 对象,所以我们直接创建一个 js 对象,也可以代替 useRef()

  • 区别: 我们创建的对象,组件每次重新渲染都会创建一个新对象;而 useRef()创建的对象,可以确保每次渲染获取到的都是同一个对象

  • 当你需要一个对象不会因为组件的重新渲染而改变时,就可以使用 useRef();

类组件

  • webstrom 中的快捷方式:

  • rsc 函数组件(不带 props)

  • rsi 函数组件(带 props)

  • rcc 类组件

  • 类组件中 state 统一存储到实例对象的 state 属性中,可以通过 this.state 来访问,通过 this.setState()对其进行修改

  • 当我们通过 this.setState()修改 state 时,React 只会修改设置了的属性,仅限于直接存储在 state 中的属性

  • xxx = React.createRef() // 创建属性存储 DOM 对象

portal

  • portal 可以将组件渲染到页面中的指定位置
  • ReactDOM.createPortal(jsx,目标位置 DOM 元素)

create-react-app

  • npx creat-react-app 项目名

  • npm run eject 不可逆 设置 webpack

  • xxx.module.css // css 的模块

  • import xxx from "./xxx.module.css"; // 引入

  • css 模块可以动态的设置唯一的 calss 值

移动端

  • 设置移动端的适配
  • 除以几视口的宽度就是多少 rem,设置视口的总宽度为 750rem
  • document.documentElement.style.fontSize = 100 / 750 + 'vw'

Context

  • 不同组件间共享数据的方式。

  • Context 相当于一个公共的存储空间,我们可以将多个组件中都需要访问的数据统一存储到一个 Context 中,这样无需通过 props 逐层传递,即可使组件访问到这些数据

  • 通过 React.createContext()创建 context

  • store 文件夹存放数据

  • xxx.js 文件

    import React from 'react';
    
    const TestContext = React.createContext({
      name: '张三',
      age: 18
    })
    export default TestContext;
    

组件 A

  • 使用方式一

  • 1、引入 context

  • 2、使用 XXX.Consumer 组件来创建元素

  • Consumer 的标签体需要一个回调函数,它会将 context 设置为回调函数的参数,通过参数就可以访问到 context 中存储的数据

  • Consumer 消费者

    import TestContext from "./xxx";
    <TestContext.Consumer>
      {(ctx) => {
        return <div>{ctx.name} - {ctx.age}</div>
      }}
    </TestContext.Consumer>
    

组件 b

  • 使用 Context 方式二;

  • 1、导入 Context

  • 2、使用钩子函数 useContext()获取到 context

  • useContext()需要一个 Context 作为参数

  • 它会将 Context 中数据获取并且作为返回值返回

  • Xxx.Provider

  • 表示数据的生产者,可以使用它来指定 Context 中的数据

  • 通过 value 来指定 Context 中存储的数据,

  • 这样一来,在盖组件的所有的子组件中都可以通过 Context 来访问它所指定数据。

  • 当我们通过 Context 访问数据时,读取离他最近的 Provider 中的数据,

  • 如果没有 Provider,则读取 context 中的默认数据

    import TestContext from "./xxx";
    // 使用钩子函数获取Context
    const ctx = useContext(TestContext);
    <div>{ctx.name} ---{ctx.age}</div>
    
  • 阻止冒泡:e.stopPropagation();

  • 字体图标:fontawesome

  • React Developer Tools

useEffect

  • Effect 副作用

  • Too many re-renders

  • 当我们直接在函数体中调用 setState 时,就好触发上述错误

  • setState()的执行流程(函数组件)

  • setCount() ===>dispatchSetDate()

  • 会先判断,组件当前处于什么阶段

  • 如果是渲染阶段--->不会检查 state 值是否相同

  • 如果不是渲染阶段--->会检查 state 的值是否相同

  • 如果值不相同,则对组件进行重新渲染

  • 如果值相同,则不对组件进行重新渲染

  • 如果值相同,React 在一些情况下会继续执行当前组件的渲染,但是这个渲染不会触发其子组件的渲染,这次渲染不会产生实际的效果

  • 这种情况通常发生在值第一次相同时

  • useEffect()是一个钩子函数,需要一个函数作为参数

  • 这个作为参数的函数,将会在组件渲染完毕后执行

  • 在 useEffect()可以传递一个第二个参数

  • 第二个参数是一个数组,在数组中可以指定 Effect 的依赖想

  • 指定后,只有当依赖发生变化时,Effect 才会被触发

  • 通常会将 Effect 中使用的所有的局部变量都设置为依赖项

  • 这样一来可以确保这些值发生变化时,会触发 Effect 的执行

  • 如果依赖项设置了一个空数组,则意味 Effect 只会在组件初始化时触发一次

  • 降低数据过滤的次数,提高用户体验,

  • 用户输入完了在过滤,用户输入的过程中,不用过滤

  • 当用户停止输入动作 1 秒后,我们才做查询

  • 在开启一个定时器的同事,应该关掉上一次

    useEffect(() => {
      const timer = setTimeout(() => {
      },1000)
    
      // 在Effect的回调函数中,可以指定一个函数作为返回值
      // 这个函数可以称其为清理函数,塔会在下次Effect执行钱调用
      // 可以在这个函数中,做一些工作来清除上次Effect执行所带来的影响
      return () => {
        clearTimeout(timer)
      }
    },[xxx])
    

useReducer

  • 可以对 state 进行整合的工具,翻译为“整合器”

  • useReducer(reducer,initialArg,init)

  • 参数:reducer 整合函数,对于我们当前 state 的所有操作都应该在该函数中定义,该函数作为返回值,会成为 state 的新值

  • reducer 在执行时,会收到两个参数

  • state: 当前最新的 state

  • action 它需要一个对象,在对象中会存储 dispatch 所发送的指令

  • initialArg: state 的初始值,作用和 useState()中的值是一样

  • 返回值 ---> 数组:

  • 第一个参数,state 用来获取 state 的值

  • 第二个参数,state 修改的派发器,通过派发器可以发送操作 state 的命令,具体的修改行为将会由另外一个函数(reducer)执行

  • const [count,countDispatch] = useReducer( (state,action) => { return state},1)

  • 可以根据 action 中不同的 type 来执行不同的操作

  • countDispatch({})

  • 为了避免 reducer 会重复创建,通常 reducer 会定义到组件的外部

      const xxx = (state, action) => {
        switch (action.type) {
          default:
            return state;
          case xxx:
            return xxx;
        }
      }
    

React.memo

  • React.memo(Index)

  • React.memo()是一个高阶组件

  • 它接收另一个组件作为参数,并且会返回一个包装过的新组件

  • 包装过的新组件就会具有缓存功能

  • 包装过后,只有组件的 props 发生变化时才会触发组件的重新渲染,否则总是返回缓存中结果

  • 对函数缓存

useCallback()

  • useCallback 是一个钩子函数,用来创建 React 中的回调函数

  • useCallback 创建的回调函数不会总在组件重新渲染时重新创建

  • useCallback() 参数

  • 1、回调函数

  • 2、依赖数组

  • 当依赖数组中的变量发生变化时,回调韩式才会重新渲染

  • 如果不指定依赖数组,回调函数每次都会重新创建

  • 一定要将回调函数中使用到的所有变量都设置成依赖项除了(setState)

      const onAdd = useCallback(() => {
        xxx
      },[])
    

Strapi

  • npm 安装
  • npx create-strapi-app@latest demo --quickstart
  • yarn
  • yarn create strapi-app demo --quickstart

Fetch API

  • fetch 浏览器自带

  • featch() 用来向服务器发送请求加载数据,是 Ajax 的升级版

  • 它需要两个参数:1、请求地址 2、请求信息(可省略)

      fetch('xxx')
      .then((res) => {
        // 判断是否正常返回响应信息
        if(res.ok) {
          // response 表示响应信息
          return res.json(); // 该方法可以将响应的json直接转换为js对象
        }
        // 代码运行到这里,说明没有成功加载数据
        // 抛出一个错误
        throw new Error('数据加载失败!')
      })
      .then(data => {
      })
      .catch((err) => {
        // catch中的回调函数,用来统一处理错误
        // catch 一执行,说明上述代码出错了
    
      })
    

await

useEffect(() => {
  const fetchData = async () => {
    try {
    const res = await featch('xxx');
      if(res.ok) {
        const data = await res.json();
      }else {
      throw new Error('数据加载失败!')
      }
    }catch(e) {
    }finally {
    }
  }
  fetchData();
},[])

Redux

  • 状态管理器

  • 状态(state)

  • 容器(Container)

  • 可预测(Predictable)

  • subscribe (订阅)

  • dispatch (派发)

  • 网页中使用 redux 的步骤:

  • 1、引入 reduxh 核心包

  • 2、创建 reducer 整合函数

  • 3、通过 reducer 对象创建 store

  • 4、对 store 中的 state 进行订阅

  • 5、通过 dispatch 派发 state 的操作指令

      const subBtn = document.getElementById('sub');
      const addBtn = document.getElementById('add');
      const countSpan = document.getElementById('countSpan')
    
      function reducer(state,action) {
        <!-- state表示当前state,可以根据这个state生成新的state
        action是一个js对象,它里边会保存操作的信息 -->
        switch (action.type) {
          case "ADD":
            return state + 1;
          case "SUB":
            return state -1;
          default:
            return state;
        }
      }
      const store = Redux.createStore(reducer,1);
      store.subscribe(() => {
        countSpan.innerText = store.getState();
    
      })
      subBtn.addEventListener('click',() => {
        stroe.dispatch({type: 'SUB'})
      })
      addBtn.addEventListener('click',() => {
        store.dispatch({type: 'ADD'})
      })
    

Redux Toolkit(RTK)

  • Redux 工具包

  • npm 安装

  • npm install react-redux @reduxjs/toolkit -S

  • yarn 安装

  • yarn add react-redux @reduxjs/toolkit

  • store/index.js

      // 使用RTK来构建store
      import { configureStore } from "@reduxjs/toolkit";
      import { stuReducer } from "./stuSlice";
      import { schoolReducer } from "./schoolSlice";
      // 创建store 用来创建store 对象,需要一个配置对象作为参数
      const store = configureStore({
        reducer: {
          student: stuReducer,
          school: schoolReducer
        }
      })
      export default store;
    
  • store/schoolSlice.js

      // 创建学校的slice
      import { createSlice } from "@reduxjs/toolkit";
      const schoolSlice = createSlice({
        name: 'school',
        initialState: {
          name: '花果山一小',
          address: "花果山大街28号"
        },
        reducers: {
          setName: (state,action) {
            state.name = action.payload;
          },
          setAddress(state,action) {
            state.address = action.payload;
          }
        }
      })
      export const { setName, setAddress } = schoolSlice.actions;
      export const { reducer: schoolReducer } = schoolSlice;
    
  • store/stuSlice.js

      // createSlice 创建reducer的切片
      // 它需要一个配置对象作为参数,通过对象的不同属性来指定它的配置
      import { createSlice } from "@reduxjs/toolkit";
      const stuSlice = createSlice({
        name: 'stu', // 用来自动生成action中的type
        initialState: {
          name: '孙悟空'.
          age: 18,
          gender: '男',
          address: '花果山'
        }, //  state的初始值
        reducers: { // 指定state的各种操作,直接在对象中添加方法
          setName(state, action) {
            // 可以通过不同的方法来指定对state的不同操作
            // 两个参数,state这个state的是一个代理对象,可以直接修改
            state.name = action.payload;
          },
          setAge(state, action) {
            state.age = action.payload;
          }
        }
      })
      // 切片对象会自动的帮助我们生成action
      // actions中存储的是slice自动生成action创建器(函数),调用函数后会自动创建action对象
      // action对象的结构 {type:name/函数名,payload: 函数的参数}
      export const { setName, setAge } = stuSlice.actions;
      export const { reducer: stuReducer } = stuSlice;
    
  • App.js

      import React from "react";
      import { useDispatch, useSelector } from "react-redux";
      import { setName, setAge } from "./store/stuSlice";
      import { setName as setSchoolName, setAddress as setSchoolAddress } from "./store/schoolSlice";
      const App = () => {
        // useSelector() 用来加载state中的数据
        // const student = useSelector(state => state.student);
        // 引入学校的state
        // const school = useSelector(state => state.school);
        const [ student,school ] = useSelector(state => state);
        // 通过useDispatch()来获取派发器对象
        const dispatch = useDispatch();
        // 获取action的构建器
        const setNameHandler = () => {
          dispatch(setName('沙和尚'))
        }
        const setAgeHandler = () => {
          dispatch(setAge(33))
        }
        return (
          <div>
            <p>{student.name} ---{student.age} --- {student.gender} --- {student.address}</p>
            <button onClick={setNameHandler}>修改name</button>
            <button onClick={setAgeHandler}>修改age</button>
            <p>{school.name} --- {school.address}</p>
            <button onClick={() => dispatch(setSchoolName('高老庄中小'))}>修改学校名字</button>
            <button onClick={() => dispatch(setSchoolAddress('高老庄19号'))}>修改学校地址</button>
          </div>
        )
      }
    
  • index.js

      import ReactDOM from "react-dom/client";
      import App from "./app";
      import { Provider } from "react-redux";
      import store from "./store";
    
      const root = ReactDOM.createRoot(document.getElementById('root'));
      root.render(
        <Provider store={store}>
          <App />
        </Provider>
      )
    

RTKQ

  • RTK Query
  • store\studentApi.js

    import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";
    // 创建Api对象
    // createApi() 用来创建RTKQ中的API对象
    // RTKQ的所有功能都需要通过该对象来进行
    // createApi()需要一个对象作为参数
    const studentApi = createApi({
      reducerPath: "studentApi", // Api的标识,不能和其他的API或reducer重复
      baseQuery: fetchBaseQuery({
        baseUrl: 'https:xxxx/api/'
      }),// 指定查询的基础信息,发送请求使用的工具
      endpoints(build) {
        // build是请求的构建器,通过build来设置请求的相关信息
        return {
          getStudents: build.query({ // 删除/新增/编辑改成mutation
            query() {
              // 用来指定请求子路径
              return "xxx";
            },
            // transformResponse 用来转换响应数据的格式
            transformResponse(baseQueryReturnValue, meta, arg) {
              return baseQueryReturnValue.data
            },
            keepUnusedDataFor: 0, // 设置数据缓存的时间,单位:秒 默认60S
          })
        }
      } // endpoints 用来指定Api中的各种功能,是一个方法,需要一个对象作为返回值
    })
    // Api对象创建后,对象中会根据各种方法自助的生成对应的钩子函数
    // 通过这些钩子函数,可以来想服务器发送请求
    // 钩子函数的命名规则 getStudents --> useGetStudentsQuery
    export const { useGetStudentsQuery } = studentApi;
    export default = studentApi;
    
  • store/index.js

    import { configuerStore } from "@reduxjs/toolkit";
    import studentApi from "./studentApi";
    const store = configureStore({
      reducer: {
        [studentAPi.reducerPath]: studentApi.reducer
      },
      middleware: getDefaultMiddleware =>
        getDefaultMiddleware().concat(studentApi.middleware)
    });
    setupListeners(store,dispatch); // 设置以后,将会支持 refetchOnFocus 和refetchOnReconnect
    export default store;
    
  • App.js

    import React from "react";
    import { useGetStudentsQuery } from "./store/studentApi";
    const App = () => {
      // 调用Api查询数据
      // 这个钩子函数它会返回一个对象作为返回值,请求过程中相关数据都在该对象中存储
      const { data, isSuccess, isLoading } = useGetStudentsQuery(); // 调用Api中的钩子查询数据
      return (
        <div>
          { isLoading && <p>数据加载中</p>}
          { isSuccess && data.data.map(item => <p key={item.id}>
            {item.attributes.name}
          </p>)}
        </div>
      )
    }
    
  • index.js

      import ReactDOM from "react-dom/client";
      import App from "./app";
      import { Provider } from "react-redux";
      import store from "./store";
    
      const root = ReactDOM.createRoot(document.getElementById('root'));
      root.render(
        <Provider store={store}>
          <App />
        </Provider>
      )
    

useQuery 的返回值

  • 返回对象
  • currentData: undefined // 当前参数的最新数据
  • data: undefined // 最新的数据
  • isError: false // 布尔值,是否有错误
  • error: Error() // 对象,有错时才存在
  • isFetching: true // 布尔值,数据是否在加载
  • isLoading: true // 布尔值,数据是否第一次加载
  • isSuccess: false // 布尔值,请求是否成功
  • isUninitialized: false // 布尔值,请求是否还没有开始发送
  • refetch: f() // 一个函数,用来重新加载数据
  • status: "pending" // 字符串,请求的状态

useQuery 的参数

  • useQuery 可以接收一个对象作为第二个参数,通过该对象可以对请求进行配置
  • selectFromResult: result => { return result; } // 用来指定 useQuery 返回的结果
  • pollingInterval: 0, // 设置轮询的间隔,单位毫秒 如果为 0 则表示不轮询
  • skip: false, // 设置是否跳过当前请求,默认 false
  • refetchOnMountOrArgChange: false, // 设置是否每次都重新加载数据 false 正常使用缓存 true 每次都重载数据 数字,数据缓存的时间(秒) 默认是 false
  • refetchOnFocus: false , // 是否在重新获取焦点时重载数据 默认 false
  • refetchOnReconnect: false, // 是否在重新连接后重载数据 默认 false

React Router

  • Router 版本 5
  • npm 安装 npm install react-router-dom@5 -S
  • yarn 安装 yarn add react-router-dom@5
  • Link
  • NavLink
  • Prompt 组件(离开页面出现确认效果)
  • Redirect 组件(重定向)
  • Route V6

  • Routes V6 中新增的组件,作用和 Switch 类似,都是用于 Route 的容器,Routes 中 Route 只有一个会被匹配

  • 需要通过 element 来指定要挂载的组件

    <Routes>
      <Route path="/" element={<Home />}></Route>
    </Routes>
    
  • 可以使用 useParams()来获取参数

  • useLocation() 获取当前的地址信息

  • useMatch() 检查当前 url 是否匹配某个路由

  • 如果路径匹配,则返回一个对象,不匹配则返回 null

  • const match = useMatch('/about')

  • useNavigate() 获取一个用于跳转页面的函数

    const nav = useNavigate();
    const clickHandler = () => {
      nav('/about') // 只用push,会产生历史记录
      nav('/about', {replace: true}) // 使用replace不会产生新的记录
    }
    
  • 路由嵌套

  • App.js

      <Routes>
        <Route path="/" element={<Home />}></Route>
        <Route path="about" element={<About />}>
          <Route path="hello" element={<Hello />}></Route>
        </Route>
      </Routes>
    
  • About.js

      return (
        <>
          <Outlet />
        </>
      )
    
  • Outlet

  • Outlet 用来表示嵌套路由中的组件

  • 当嵌套路由中的路径匹配成功了,Outlet 则表示嵌套路由中的组件

  • 当嵌套路由中的路径没有匹配成功,Outlet 就什么都不是

  • Navigate 组件用来跳转到指定的位置

  • 默认使用 push 挑战

  • 可以加 replace 属性

      import { Navigate } from "react-router-dom"
      return(
        <>
          <Navigate to="/student" replace>
        </>
      )
    
import { NavLink } from "react-router-dom"

  <NavLink style={({isActive}) => {
    return isActive?  { backgroundColor: 'yellow'} : null
  }}  to="/home"></NavLink>

NeedAuth 组件

  • 登录权限

  • NeedAuth.js

      import React from "react"
      import { useSelector,useLocation } from "react-redux"
      import { Navigate } from "react-router-dom"
    
      const NeedAuth = props => {
        const auth = useSelector(state => state.auth);
        const location = useLocation();
        return auth.isLogged ? props.children : <Navigate to={"/login"} replace state={{preLocation: location}} />
      }
      export default NeedAuth;
    
  • App.js

      <Routes>
        <Route path={"/"} element={<HomePage />}></Route>
        <Route path={"profile"} element={<NeedAuth><ProfilePage /></NeedAuth>}>
        <Route path={"login"} element={<LoginPage />}>
      </Routes>
    
  • 跳转页面到之前的目录

      const location = useLocation();
      const form =  loaction.state?.preLocation?.pathname || "/";
      navigate(from,{replace: true})
    
  • redux 存储在内存中刷新后就不见了

useMemo

  • React 中自带的钩子函数

  • useState

  • useEffect

  • useContext

  • useReducer

  • useCallback

  • useRef

  • useMemo

  • useImperativeHandle

  • useLayoutEffect

  • useDebugValue (18.0 新增)

  • useDeferredValue(18.0 新增)

  • useTransition(18.0 新增)

  • useId(18.0 新增)

  • useSyncExternalStore(18.0 新增)

  • useInsertionEffect(18.0 新增)

      const result = useMemo(() => {
        function sum(a,b) {
          return a + b;
        }
      },[a,b])
    
  • useMemo 用来存储函数的执行结果

useImperativeHandle

  • 子组件通过 forwardRef 包装
    ,父组件可以拿到 ref
  • React.forwardRef()
  • 可以用来指定组件向外部暴露的 ref
  • useImperativeHandle 和 forwardRef 结合使用
  • useImperativeHandle 可以用来指定 ref 返回的值

      let inputRef = useRef();
      useImperativeHandle(ref,() => {
        //回调函数的返回值,会成为ref的值
        <!-- return 123; -->
        return {
          changeInpValue(val) {
            inputRef.current.value = val;
          }
        }
      })
    

useEffect

  • 组件挂载-->state 改变-->DOM 改变-->绘制屏幕-->useEffect

useInsertionEffect

  • 组件挂载--> state 改变-->useInsertionEffect-->DOM 改变-->绘制屏幕
  • 添加元素

useLayoutEffect

  • 使用场景不多
  • 组件挂载--> state 改变-->DOM 改变-->useLayoutEffect --> 绘制屏幕
  • 调整元素样式
  • 执行顺序 useInsertionEffect -- > useLayoutEffect -->useEffect

UseDebugValue

  • 使用场景不多

useDeferredValue

  • 设置 state 的延迟值
  • useDeferredValue 需要一个 state 作为参数,会为 state 创建一个延迟值
  • 当设置了延迟值后,每次 state 修改时都会触发两次重新的渲染
  • 这两次执行对于其他的部分没有区别,但是延迟值两次执行的值是不同的
  • 第一次执行时延迟值是 state 的旧值,第二次执行时,延迟值是 state 的新值
  • 延迟值,总是会比原版的 state,慢一步更新

useTransition

  • 使用 state 的优先级
  • startTransition 的回调函数中设置 setState 会让其他的 setState 生效后才执行
  • const [isPending,startTransition] = useTransition();

UseId

  • 生成一个 id,避免重名
  • const id = useId();
posted @ 2022-11-22 17:09  不完美的完美  阅读(56)  评论(0编辑  收藏  举报