# react18 **Repository Path**: adu7/react18 ## Basic Information - **Project Name**: react18 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-31 - **Last Updated**: 2025-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README - | 格式 | 显示 | | ----------- | ---- | | `ctrl + B` | 加粗 | | `ctrl + I ` | 斜体 | | `ctrl + # ` | 标题 | | `ctrl + T ` | 表格 | - | 代码 | 显示 | | ------------------ | ---------- | | `ctrl + Shift + B` | 行内代码 | | `ctrl + Shift + K` | 多行代码 | | `ctrl + K` | 下划线链接 | # React18 > vscode插件 1. TRAE AI 2. comate ``` 创建 pnpm create vite@latest ``` > 项目目录 ``` eslint.config.js //代码规范 tsconfig.app.json //针对整个项目 tsconfig.json tsconfig.node.json //只针对vite.config.ts vite.config.ts pubilc 打包会放在dist根目录 src /assets 需要构建 加hash ``` > package.json ``` { "name": "test_react18", "private": true, "version": "0.0.0", "type": "module", //对应nodemodules/bin "scripts": { "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview" }, "dependencies": { "react": "^18.3.1", "react-dom": "^18.3.1" }, //开发环境 不会打包 "devDependencies": { "@eslint/js": "^9.15.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vitejs/plugin-react-swc": "^3.5.0", "@types/node": "^24.6.0", "eslint": "^9.15.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", "globals": "^15.12.0", "typescript": "~5.6.3", "typescript-eslint": "^8.15.0", "vite": "^6.0.1" } } ``` ## babel > js编译器 AST语法树(桥梁) -> Tranform -> Generate ``` es6 es7 -> es5 jsx -> javascript 核心库 @babel/core @babel/generate ``` ## jsx ## useState ``` const handle = () => { setCount(count + 1);//count + 1为状态 setCount(count + 1); setCount(count + 1); //异步跟新 react只在意最后的状态,不关心过程 };//1 const handle = () => { setCount((prev)=>prev+1);//(prev)=>prev+1为过程 setCount((prev)=>prev+1); setCount((prev)=>prev+1); //异步跟新 react只在意最后的状态,不关心过程 };//3 const handle = () => { setCount(1); setCount(2); setCount(3); //异步跟新 react只在意最后的状态,不关心过程 };//3 ``` ## useEffet > 依赖项更新时先执行cleanup 在执行setup 卸载时执行cleanup 返回undefined ``` 00:01 useEffect概述 1.useEffect是React中处理副作用的钩子函数,类似于生命周期方法。 2.useEffect可以在组件渲染完成、更新和卸载时处理副作用。 00:38 纯函数与副作用函数 1.纯函数:相同的输入永远得到相同的输出,不依赖外部状态,也不修改外部状态。 2.副作用函数:依赖外部状态,或在执行过程中修改外部状态。 3.常见副作用函数:修改localStorage、发送Ajax请求、操作DOM元素等。 02:56 纯函数的实现 1.不直接修改原始数据,而是创建数据的副本进行修改。 2.深拷贝:使用库函数或手动实现,确保复制对象及其所有嵌套属性。 3.浏览器原生API:使用结构化克隆或库函数进行深拷贝。 ``` ## useReducer ``` const initState = { count: -1, }; //初始化函数 只执行一次 const initfn = (state: { count: number }) => { console.log(state, '初始化函数 只执行一次'); return { count: 10, }; }; // 处理函数reducer 默认不走 const reducer = (state: { count: number }, action: { type: string }) => { // return state; console.log(state, action, '处理函数reducer'); switch (action.type) { case 'add': return { count: state.count + 1, }; case 'sub': return { count: state.count - 1, }; default: return state; } }; function App() { //第二个参数为默认值 // 第三个参数是可选的,可不传 const [state, dispath] = useReducer(reducer, initState, initfn); return ( <>
{state.count}
); } ``` ## useSyncExternalStore ``` useStorage.ts import { useSyncExternalStore } from 'react'; export const useStorage = (type: string, initValue: any) => { // 订阅者 const subscribe = (callback: () => void) => { // 订阅浏览器api window.addEventListener('storage', callback); //callback刷新视图 return () => { //取消订阅 window.removeEventListener('storage', callback); }; }; const getSnapshot = () => { //返回值和上一次不同 视图就会更新 注意:数组等引用类型时需返回新的引用 return localStorage.getItem(type) || initValue; }; const res = useSyncExternalStore(subscribe, getSnapshot); const updateStorage = (value: any) => { localStorage.setItem(type, JSON.stringify(value)); window.dispatchEvent(new StorageEvent('storage')); //通知订阅者 }; return [res, updateStorage]; }; useHistory.ts import { useSyncExternalStore } from 'react'; // 实现跳转 监听history变化 export const useHistory = () => { // 订阅者 const subscribe = (callback: () => void) => { // 订阅浏览器api 监听路由的变化 // vue的三种路由结构 ssr hash history // hash 监听hashchange 注意 只能监听浏览器的前进后退按钮 // history 监听popstate 注意 只能监听浏览器的前进后退按钮 // ssr 监听popstate window.addEventListener('hashchange', callback); //callback刷新视图 window.addEventListener('popstate', callback); return () => { //取消订阅 window.removeEventListener('storage', callback); window.removeEventListener('popstate', callback); }; }; const getSnapshot = () => { return window.location.href; }; const url = useSyncExternalStore(subscribe, getSnapshot); const push = (url: string) => { window.history.pushState({}, '', url); window.dispatchEvent(new PopStateEvent('popstate')); //手动触发popstate事件 }; const replace = (url: string) => { window.history.replaceState({}, '', url); window.dispatchEvent(new PopStateEvent('popstate')); //手动触发popstate事件 }; return [url, push, replace] as const; }; ``` ## useTranstion ``` ``` ![image-20251101232800071](D:\Workspaces\react18\README.assets\image-20251101232800071.png) > 优化hooks > 帮助你在不阻塞UI的情况下更新状态的React Hooks > 用于管理UI中的过渡状态 特别是处理长时间运行的状态更新时,它允许你将某些更新标记为过渡状态,这样React可以优先处理更重要的更新,比如用户输入,同时延迟处理过渡更新 ``` pnpm i mockjs pnpm install antd --save import type React from "react"; import { Input, List } from "antd"; import { useState, useTransition } from "react"; const Ces: React.FC = () => { const [inputvalue, setInputValue] = useState(""); const [list, setList] = useState([]); const [isPending, startTransition] = useTransition(); interface ListItem { id: string; name: string; age: number; sex: string; address: string; } const handleChange = (e: React.ChangeEvent) => { console.log(e.target.value); setInputValue(e.target.value); fetch(`/api/mock/list?key=${e.target.value}`) .then((res) => res.json()) .then((res) => { // console.log(res); setList(res.list); // startTransition(() => { // setList(res.list); // }); }); }; return ( <> {item.address}} > {/* {isPending ? (
Loading...
) : ( {item.address}} > )} */} ); }; export default Ces; ``` ## vite插件 ``` import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; import type { Plugin } from 'vite'; import mockjs from 'mockjs'; import url from 'node:url'; const viteMockServer = (): Plugin => { return { name: 'vite-plugin-mock', configureServer: (server) => { server.middlewares.use('/api/mock/list', (req, res) => { res.setHeader('Content-Type', 'application/json'); const parseurl = url.parse(req.originalUrl!, true).query; const data = mockjs.mock({ 'list|2000': [ { 'id|+1': '@guid', name: parseurl.key, age: '@integer(18, 30)', 'sex|1': ['男', '女'], address: '@county(true)', }, ], }); res.end(JSON.stringify(data)); }); }, }; }; // https://vite.dev/config/ export default defineConfig({ plugins: [react(), viteMockServer()], server: { port: 3008, }, }); ``` ## useDeferredValue ![image-20251101232922627](D:\Workspaces\react18\README.assets\image-20251101232922627.png) ![image-20251101234036252](D:\Workspaces\react18\README.assets\image-20251101234036252.png) ``` import type React from "react"; import { Input, List } from "antd"; import { useDeferredValue, useState } from "react"; import mockjs from "mockjs"; const Ces: React.FC = () => { const [inputvalue, setInputValue] = useState(""); const [list, setList] = useState(() => { return mockjs.mock({ "list|100": [ { id: "@guid", name: "@cname", age: "@integer(18, 30)", sex: "@boolean", address: "@county(true)", }, ], }).list; }); interface ListItem { id: string; name: string; age: number; sex: string; address: string; } const inputvalueDeferred = useDeferredValue(inputvalue); const handleChange = (e: React.ChangeEvent) => { console.log(e.target.value); setInputValue(e.target.value); }; const findName = () => { return list.filter((item) => item.name.includes(inputvalueDeferred)); }; const isSame = () => { return inputvalueDeferred === inputvalue; }; return ( <> ( {item.name}
{item.address}
)} >
); }; export default Ces; ``` ## useRef ![image-20251101234433962](D:\Workspaces\react18\README.assets\image-20251101234433962.png) ![image-20251102002519870](D:\Workspaces\react18\README.assets\image-20251102002519870.png) ``` import React, { useRef } from "react"; const Ces: React.FC = () => { const domRef = useRef(null); //null 表示一个空对象 //undefined obj obj.a的a 没有定义 就为undefined const handleClick = () => { console.dir(domRef.current); domRef.current!.style.color = "red"; }; return ( <>
AAA
BBB
CCC
); }; export default Ces; import React, { useRef, useState } from "react"; const Ces: React.FC = () => { const domRef = useRef(null); const [count, setCount] = useState(0); // let num = 0; let num = useRef(0); console.log("App -- render"); // useState 每次渲染都会重新创建Ces这个组件 num也会初始化为0 const handleClick = () => { setCount((old) => { num.current = old + 1; return old + 1; }); console.log(num, count); }; return ( <>
数据存储
{count}:{num.current}
); }; export default Ces; ``` ## useImperativeHandle ![image-20251102231433776](D:\Workspaces\react18\README.assets\image-20251102231433776.png) ![image-20251102232831429](D:\Workspaces\react18\README.assets\image-20251102232831429.png) ``` import React, { useImperativeHandle, useRef, useState } from "react"; const Son = React.forwardRef((props, ref) => { const [count, setCount] = useState(0); useImperativeHandle( ref, () => ({ getCount() { console.log("getCount"); }, count, setCount, }), [] ); return (

子组件:{count}
); }); const Ces: React.FC = () => { const childRef = useRef(null); const handleClick = () => { console.log(childRef.current.count); }; const handleAdd = () => { childRef.current.setCount(childRef.current.count + 1); }; return ( <>
我是父组件
); }; export default Ces; 主要用于弹窗父子组件 子组件将form校验等函数暴露出去 import React, { useImperativeHandle, useRef, useState } from "react"; const Son = React.forwardRef((props, ref) => { const [form, setForm] = useState({ name: "", password: "", }); const vaidator = () => { console.log(form); if (form.name.length === 0) { return "name不能为空"; } if (form.password.length === 0) { return "password不能为空"; } }; const resetForm = () => { setForm({ name: "", password: "", }); }; useImperativeHandle( ref, () => ({ vaidator, resetForm, }) ); return (
{ console.log(e.target.value,'33'); setForm({ ...form, name: e.target.value, }); }} /> { setForm({ ...form, password: e.target.value, }); }} />
); }); const Ces: React.FC = () => { const childRef = useRef(null); const handlevaidator = () => { console.log(childRef.current.vaidator()); }; const handlereset = () => { childRef.current.resetForm(); }; return ( <>
我是父组件
); }; export default Ces; ``` ## useContext ![image-20251102234819890](D:\Workspaces\react18\README.assets\image-20251102234819890.png) ![image-20251102234925431](D:\Workspaces\react18\README.assets\image-20251102234925431.png) ``` import React, { useImperativeHandle, useRef, useState } from "react"; interface ThemeContextType { theme: string; } const ThemeContext = React.createContext({ theme: "light", }); const Sonson = () => { const { theme } = React.useContext(ThemeContext); console.log(theme, "sonson"); const lightStyle = { color: "white", backgroundColor: "black", }; const darkStyle = { color: "black", backgroundColor: "white", }; return
sonson
; }; const Son = () => { const { theme } = React.useContext(ThemeContext); console.log(theme, "son"); const lightStyle = { color: "white", backgroundColor: "black", }; const darkStyle = { color: "black", backgroundColor: "white", }; return (
son
); }; const Ces: React.FC = () => { const [theme, setTheme] = useState("light"); const handleClick = () => { setTheme(theme === "light" ? "dark" : "light"); }; return ( <> ); }; export default Ces; ``` ## React原理 ![image-20251103152221583](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103152221583.png) ![image-20251103154234671](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103154234671.png) ![image-20251103154425632](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103154425632.png) ![image-20251103154447960](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103154447960.png) ![image-20251103154849202](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103154849202.png) ![image-20251103154856606](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103154856606.png) ![image-20251103163509687](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103163509687.png) ## 调度器 ![image-20251103163641992](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103163641992.png) ![image-20251103164103232](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103164103232.png) ## TS ![image-20251103171258013](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103171258013.png) > 区别:接口和type区别 ![image-20251103172030782](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103172030782.png) > keyof > > ![image-20251103172305869](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103172305869.png) ![image-20251103172255764](C:\Users\17749\AppData\Roaming\Typora\typora-user-images\image-20251103172255764.png) ## reactRouter > pnpm i react-router-dom ![image-20251103234344463](D:\Workspaces\react18\README.assets\image-20251103234344463.png) ![image-20251103235701963](D:\Workspaces\react18\README.assets\image-20251103235701963.png) ``` import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App.tsx"; import ReactDemo from "./React.tsx"; import EmptyPage from "./404.tsx"; import "./components/Message/index.tsx"; import { BrowserRouter, Routes, Route, Navigate, HashRouter, } from "react-router-dom"; createRoot(document.getElementById("root")!).render( {/* */} } /> } /> } /> ); function App() { //第二个参数为默认值 // 第三个参数是可选的,可不传 const [state, dispath] = useReducer(reducer, initState, initfn); const [count, setCount] = useStorage('ss', 22); const [url, push, replace] = useHistory(); return ( <>
NavLink to home
Link to home
{state.count}
{/*
{count}
{url}
*/} {/* */} ); } ```