文章目录
- [React 基础](#React 基础)
-
- 一、基础概念
- 二、组件化
- 三、状态
- 四、属性
- 五、项目初始化
- 六、jsx
- [七、创建 React 组件的两种方式](#七、创建 React 组件的两种方式)
- [八、常用的 hooks](#八、常用的 hooks)
-
- 1、useState:用来修改状态值
- [2、useReducer:用来修改状态值,比 useState 更适合处理复杂逻辑](#2、useReducer:用来修改状态值,比 useState 更适合处理复杂逻辑)
- 3、useContext:传递数据
- [4、useMemo: 缓存计算结果](#4、useMemo: 缓存计算结果)
- 5、useCallback:缓存函数
- 6、useEffect:副作用函数
- 7、useId:设置id
- 8、useImperativeHandle:用来给子组件绑定一些方法,让父组件可以直接调用子组件的方法
- [9、useTransition:主要用于在组件中实现非阻塞式更新(异步 UI 更新)](#9、useTransition:主要用于在组件中实现非阻塞式更新(异步 UI 更新))
- 10、useDeferedValue:用于将状态更新延迟到更紧急的更新之后执行
- [12、useSyncExternalStore:是 React 官方推荐的方式,用于安全、高效地接入外部状态源,尤其适用于构建状态管理库或需要响应外部数据变化的场景](#12、useSyncExternalStore:是 React 官方推荐的方式,用于安全、高效地接入外部状态源,尤其适用于构建状态管理库或需要响应外部数据变化的场景)
- 样式方案
- 状态方案
React 基础
一、基础概念
声明式 UI,ui=render(state)
- 声明式,定义状态,修改状态,将状态编写入 jsx
- 组件化,(区块化,原子应用)
- 虚拟 DOM,但是可以这样说,这个方案放在当下已经不是一个了不起的方案,FragmentDocument,没有虚拟 dom 的代表作 solidjs
- 单向数据流。(Vue -> MVVM)
- JSX,对开发者友好,但加重编译器的负担
二、组件化
jsx
// 类组件
class Welcome extends React.Component {
render() {
return <div>123</div>;
}
}
// 函数组件
function Welcome() {
return <div>123</div>;
}
三、状态
jsx
// 类组件
class Welcome extends React.Component {
constructor() {
this.state = {
name: "heyi",
};
}
render() {
return <div>123</div>;
}
}
// 函数组件
function Welcome() {
const [count, setCount] = useState(0);
return <div>123</div>;
}
四、属性
jsx
function Welcome(props) {
return <div>{props.name}</div>;
}
五、项目初始化
项目初始化其实就是我们平常所说的工程化
在初始化时,我们需要考虑这个项目用什么语言(js、ts),打包(webpack、vite),编译(babel、swc、rspack、esbuild),技术栈 React
接下来如果是企业级项目,除了技术层内容考虑以外,还需要重点关注:流程化、自动化、规范化等。
-
使用 vite 自己从零搭建
-
1、安装依赖
json{ "dependencies": { "react": "^19.1.0", "react-dom": "^19.1.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.6.0", "vite": "^7.0.2" } }
-
2、编写 vite.config.js 文件
jsimport { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()], server: { port: 3000, }, });
-
3、在项目根目录创建 index.html 文件
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="root"></div> <script type="module" src="/src/main.js"></script> </body> </html>
-
4、创建 src/main.js
jsimport { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' createRoot(document.getElementById('root')!).render( <StrictMode> <App /> </StrictMode>, )
-
5、创建 App.tsx
tsximport { useState } from "react"; function App() { return <div>123</div>; } export default App;
-
6、编写启动脚本
json"scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview", "test": "echo \"Error: no test specified\" && exit 1" },
-
7、启动项目
bashpnpm run dev
-
-
使用脚手架,不用关心初始化的细节
-
vite
bashpnpm create vite react-vite-cli-demo --template react-ts
-
create-react-app
bashnpx create-react-app react-cra-demo --template typescript
-
六、jsx
jsx 全称是:javaScript and xml,在 javascript 代码中编写 html 代码是一种规范。因为规范是为编辑器设计的。
jsx
const element = <h1>Hello world!</h1>;
jsx 通过编译器进行转化,babel(@babel/preset-react、plugin-transform-react-jsx)
通过 jsx 转化后,代码就变成 js 引擎可以执行的代码了。
js
import { jsx as _jsx } from "react/jsx-runtime";
var element = _jsx("h1", {
children: "Hello world!",
});
再在 react 运行时,通过 react 定义的 jsx 创建出 ReactElement
js
return ReactElement(
type,
key,
ref,
undefined,
undefined,
getOwner(),
props,
undefined,
undefined
);
七、创建 React 组件的两种方式
函数式组件(推荐)
tsx
import React, { useState } from "react";
interface FCCBasicProps {
name: string;
}
export const FCCBasic: React.FC<FCCBasicProps> = (props: FCCBasicProps) => {
const [count, setCount] = useState(0);
return (
<div
onClick={() => {
setCount(count + 1);
}}
>
Hello, Functional Component Basic! count: {count}
</div>
);
};
类组件(不推荐)
tsx
import React from "react";
export interface BasicProps {
name: string;
}
export interface BasicState {
count: number;
}
export class Basic extends React.Component<BasicProps, BasicState> {
constructor(props: BasicProps) {
super(props);
this.state = {
count: 0,
};
}
render() {
console.log(this.props.name);
return (
<div
onClick={() => {
this.setState({
count: this.state.count + 1,
});
}}
>
Hello, Class Component Basic!{this.state.count}
</div>
);
}
}
八、常用的 hooks
- useState: 用于状态管理
- useEffect: 用于数据获取、定时器、订阅、动画
- useContext: 用于数据共享
- useReducer: 状态管理
- useMemo: 缓存数据
- useRef: 获取 DOM 元素
- useCallback: 缓存函数
1、useState:用来修改状态值
ts
import React, { useState } from "react";
interface UseStateDemoProps {}
export const UseStateDemo: React.FC<UseStateDemoProps> = () => {
const [count, setCount] = useState(0);
return (
<div onClick={() => setCount((c) => c + 1)}>
Hello, Functional Component UseStateDemo!{count}
</div>
);
};
2、useReducer:用来修改状态值,比 useState 更适合处理复杂逻辑
ts
import React, { useReducer } from "react";
type INCREMENT = "increment";
type DECREMENT = "decrement";
type Action = {
type: INCREMENT | DECREMENT;
};
type State = {
count: number;
};
interface ReducerProps {}
const reducer = (state: State, action: Action) => {
switch (action.type) {
case "increment":
return { ...state, count: state.count + 1 };
case "decrement":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export const UseReducerDemo: React.FC<ReducerProps> = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div onClick={() => dispatch({ type: "increment" })}>
Hello,Functional Component useReducerDemo{state.count}
</div>
);
};
3、useContext:传递数据
ts
import React, { useContext } from "react";
interface UseContextProps {}
// 一定要结合 Context
const UserContext = React.createContext({ name: "default" });
// 提供者和消费者
export const UseContextDemo: React.FC<UseContextProps> = () => {
return (
<UserContext.Provider value={{ name: "jack" }}>
<Child />
</UserContext.Provider>
);
};
// 老版本写法
// const Child = () => {
// return (
// <UserContext.Consumer>
// {(value) => <div>{value.name}</div>}
// </UserContext.Consumer>
// );
// };
// 新版本基于 hooks 的写法
const Child = () => {
const user = useContext(UserContext);
return <div>{user.name}</div>;
};
4、useMemo: 缓存计算结果
ts
import React, { useMemo, useState } from "react";
interface UseMemoProps {}
export const UseMemoDemo: React.FC<UseMemoProps> = () => {
const [count, setCount] = useState(0);
const [price, setPrice] = useState(0);
// 这个时候我想计算一个 Count 的二倍数,并且我们假设这个计算非常复杂,只在count更新时重新计算
const doubleCount = useMemo(() => {
console.log("只有count改变时才计算...");
return count * 2;
}, [count]);
return (
<div
onClick={() => {
if (price % 2 === 0) {
setCount((c) => c + 1);
}
setPrice((p) => p + 1);
}}
>
{doubleCount}----{price}
</div>
);
};
5、useCallback:缓存函数
ts
import React, { useCallback, useState } from "react";
interface UseCallbackProps {}
export const UseCallbackDemo: React.FC<UseCallbackProps> = () => {
const [count, setCount] = useState(0);
const [price, setPrice] = useState(0);
// 只有count发生变化后才重新创建函数
const handleClick = useCallback(() => {
console.log("~ handleClick ~ count: ", count);
}, [count]);
return (
<div onClick={handleClick}>
UseCallbackDemo,count:{count}-------{price}
<div
onClick={() => {
setCount((c) => c + 1);
}}
>
+ count
</div>
<div
onClick={() => {
setPrice((c) => c + 1);
}}
>
+ price
</div>
</div>
);
};
6、useEffect:副作用函数
ts
import React, { useEffect, useState } from "react";
export const UseEffectDemo: React.FC = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("useEffect");
document.title = `you clicked ${count} times`;
// 返回一个方法用来清除副作用
return () => {
console.log("clean up");
};
}, [count]);
return (
<div>
<p>UseEffectDemo</p>
<button onClick={() => setCount((c) => c + 1)}>click me</button>
</div>
);
};
7、useId:设置id
ts
import React, { useId } from "react";
export const UseIdDemo = () => {
const id = useId();
return (
<div>
<label htmlFor={id}>Name</label>
<input id={id} type="text" />
</div>
);
};
8、useImperativeHandle:用来给子组件绑定一些方法,让父组件可以直接调用子组件的方法
ts
import React, { forwardRef, useImperativeHandle, useRef } from "react";
interface FancyInputHandle {
focus: () => void;
select: () => void;
}
// 但如果你希望父组件可以调用子组件中定义的方法(而不是直接访问 DOM),就需要使用 useImperativeHandle 来定制 ref 的内容。
const FancyInput = forwardRef<FancyInputHandle>((props, ref) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current?.focus();
},
select: () => {
inputRef.current?.select();
},
}));
return <input ref={inputRef} />;
});
export function UseImperativeHandleDemo() {
const inputRef = useRef<HTMLInputElement>(null);
return (
<div>
<FancyInput ref={inputRef} />
<button
onClick={() => {
inputRef.current?.focus();
}}
>
Focus the input
</button>
</div>
);
}
9、useTransition:主要用于在组件中实现非阻塞式更新(异步 UI 更新)
ts
import React, { useState, useTransition } from "react";
export function UseTransitionDemo() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
const handleClick = () => {
startTransition(() => {
setCount((c) => c + 1);
});
};
return (
<div>
<button onClick={handleClick}>Increment</button>
{isPending ? "Loading..." : <p>{count}</p>}
</div>
);
}
10、useDeferedValue:用于将状态更新延迟到更紧急的更新之后执行
ts
import React, { useDeferredValue } from "react";
export const UseDeferedValueDemo: React.FC = () => {
const [text, setText] = React.useState("");
const deferredText = useDeferredValue(text);
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<div>{deferredText}</div>
</div>
);
};
12、useSyncExternalStore:是 React 官方推荐的方式,用于安全、高效地接入外部状态源,尤其适用于构建状态管理库或需要响应外部数据变化的场景
ts
import React, { useSyncExternalStore } from "react";
function useWindowWidth() {
return useSyncExternalStore(
(cb) => {
window.addEventListener("resize", cb);
return () => window.removeEventListener("resize", cb);
},
() => window.innerWidth,
() => window.innerWidth
);
}
export const UseSyncExternalStoreDemo: React.FC = () => {
const width = useWindowWidth();
return (
<div>
<div>window width: {width} </div>
</div>
);
};
样式方案
- 内联方案
<i style={``{color: "blue"}}>哈哈</i>
- module css
- css in js
- tailwind css
状态方案
- useState
- useReducer
- useContext
- useSyncExternalStore
- redux
- mobx
- zustand
- jotai
- recoil