Files
flys_blog/docs/notes/react.md
T
2025-06-13 16:30:38 +08:00

359 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 1. React
## 1.1 脚手架文件结构
```
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.svg
│ ├── components: 存放组件
│ │ └── HelloWorld.jsx
│ ├── App.jsx: 汇总所有组件
│ └── index.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
└── package-lock.json:包版本控制文件
```
## 1.2 React 核心概念
### 1.2.1 JSX
#### 1. 定义
JSX 是 JavaScript XML 的缩写,它允许在 JavaScript 代码中编写类似 HTML 的结构,最终会被 Babel 等工具编译为 React 元素。
#### 2. 基本语法
JSX 看起来像 HTML,但实际上是 JavaScript 语法扩展,必须包含在一个根元素中。示例:
```jsx
const element = (
<div>
<h1>Hello, world!</h1>
<p>Welcome to React.</p>
</div>
);
```
#### 3. 表达式嵌入
在 JSX 中可以使用花括号 `{}` 嵌入 JavaScript 表达式。示例:
```jsx
const name = 'Alice';
const element = <h1>Hello, {name}</h1>;
```
#### 4. 样式处理
在 JSX 中使用 `style` 属性设置内联样式,属性值为一个 JavaScript 对象,键采用驼峰命名法。示例:
```jsx
const element = <div style={{ color: 'blue', fontSize: '20px' }}>Styled text</div>;
```
#### 5. 类名设置
由于 `class` 是 JavaScript 保留字,在 JSX 中使用 `className` 来设置 HTML 元素的类名。示例:
```jsx
const element = <div className="container">Container element</div>;
```
### 1.2.2 组件
#### 1. 函数组件
函数组件是一个返回 JSX 的 JavaScript 函数,接收 `props` 作为参数。示例:
```jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
```
#### 2. 类组件
类组件继承自 `React.Component`,必须实现 `render` 方法返回 JSX。示例:
```jsx
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
```
### 1.2.6 事件处理
在 React 中,事件处理与 HTML 类似,但采用驼峰命名法,并且通过传递函数来处理事件。示例:
```jsx
function Button() {
const handleClick = () => {
alert('Button clicked!');
};
return (
<button onClick={handleClick}>Click me</button>
);
}
```
### 1.2.7 条件渲染
在 React 中可以使用 JavaScript 逻辑进行条件渲染。示例:
```jsx
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please sign up.</h1>;
}
```
还可以使用三元运算符和逻辑与运算符进行条件渲染:
```jsx
// 三元运算符
const element = isLoggedIn ? <LogoutButton /> : <LoginButton />;
// 逻辑与运算符
const unreadMessages = ['React', 'Re: React', 'Re:Re: React'];
const element = (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && (
<h2>You have {unreadMessages.length} unread messages.</h2>
)}
</div>
);
```
### 1.2.3 状态(State
1. 功能:用于管理组件内部的数据。
2. 示例:
```jsx
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
```
### 1.2.4 生命周期方法
1. `componentDidMount()`:组件挂载后执行,常用于数据请求。
2. `componentDidUpdate()`:组件更新后执行。
3. `componentWillUnmount()`:组件卸载前执行,常用于清理工作。
### 1.2.5 状态提升
当多个组件需要共享状态时,通常会将状态提升到最近的共同父组件中。通过父组件传递 `props` 和回调函数,实现子组件与父组件之间的状态同步。
```jsx
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
```
## 1.3 React Hooks
### 1.3.1 useState
`useState` 是一个基础的 Hook,用于在函数组件中添加状态。示例如下:
```jsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
### 1.3.2 useEffect
`useEffect` 可以让你在函数组件中执行副作用操作,比如数据获取、订阅或手动修改 DOM。示例如下:
```jsx
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
```
## 1.4 React 路由
### 1.4.1 基本使用
1. 安装:`npm install react-router-dom`
2. 示例:
```jsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}
function Home() {
return <h1>Home Page</h1>;
}
function About() {
return <h1>About Page</h1>;
}
```
## 1.5 React 上下文(Context
### 1.5.1 功能
用于在组件树中共享数据,避免逐层传递 props。
### 1.5.2 示例
```jsx
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext();
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>I am styled by theme context!</button>;
}
```
## 1.6 React 优化
### 1.6.1 `React.memo`
用于优化函数组件,避免不必要的渲染。
```jsx
const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});
```
### 1.6.2 `useCallback` 和 `useMemo`
1. `useCallback`:缓存函数,避免每次渲染都重新创建。
- **原理**`useCallback` 接收一个回调函数和依赖项数组作为参数,返回一个 memoized 版本的回调函数,该回调函数仅在某个依赖项改变时才会更新。这有助于在传递回调函数给子组件时,避免不必要的重新渲染。
- **使用场景**:当你将回调函数作为 props 传递给子组件,并且子组件使用 `React.memo` 进行优化时,使用 `useCallback` 可以确保子组件不会因为回调函数的变化而不必要地重新渲染。
- **示例代码**
```jsx
import React, { useState, useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const [value, setValue] = useState('');
// 使用 useCallback 缓存函数
const handleClick = useCallback(() => {
console.log(`Count is: ${count}`);
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<Child handleClick={handleClick} />
</div>
);
}
const Child = React.memo(function Child({ handleClick }) {
return (
<button onClick={handleClick}>Click me</button>
);
});
```
2. `useMemo`:缓存计算结果,避免重复计算。
- **原理**`useMemo` 接收一个计算函数和依赖项数组作为参数,返回一个 memoized 的计算结果。仅当某个依赖项改变时,才会重新执行计算函数。
- **使用场景**:当你有一个计算开销较大的函数,并且该函数的输入依赖于某些状态或 props 时,使用 `useMemo` 可以避免在每次渲染时都重新计算结果。
- **示例代码**
```jsx
import React, { useState, useMemo } from 'react';
function App() {
const [count, setCount] = useState(0);
const [value, setValue] = useState('');
// 使用 useMemo 缓存计算结果
const expensiveValue = useMemo(() => {
console.log('Calculating expensive value...');
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<p>Expensive Value: {expensiveValue}</p>
</div>
);
}
```