# 2503
**Repository Path**: flyird/2503
## Basic Information
- **Project Name**: 2503
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 6
- **Created**: 2025-10-27
- **Last Updated**: 2025-11-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 概览
- 第1周
- React 类组件 + Router@5.3.4
- 考试内容记账本(移动端项目)
- 第2周
- React 函数组件、hooks
- TS喜马拉雅
- 考试内容基本统一(移动端项目)
- 第3周
- redux
- 蜜雪冰城后台管理(PC端)
- 第4周
- TS,蜜雪冰城后台管理(PC端)
## 相关网站
所有学习资料(上课的代码、文档):
- https://gitee.com/flyird/2503
react官网:
- [https://zh-hans.react.dev/](https://gitee.com/link?target=https%3A%2F%2Fzh-hans.react.dev%2F)
vant组件库网站:
- [https://react-vant.3lang.dev/](https://gitee.com/link?target=https%3A%2F%2Freact-vant.3lang.dev%2F)
antd组件库网站:
- 最新网站:[https://ant.design/index-cn](https://gitee.com/link?target=https%3A%2F%2Fant.design%2Findex-cn)
- 备用网站:https://4x-ant-design.antgroup.com/index-cn
redux官网:
- [https://cn.redux.js.org/index.html](https://gitee.com/link?target=https%3A%2F%2Fcn.redux.js.org%2Findex.html)
## 安装react项目
> 最新版是19(2024年3月25日发布),我们学习的是react18版本。
安装命令:
```
pnpm create vite
回车
* Project name:
| vite-project(这里填写项目名称,就是文件夹名称)
—
回车
* Select a framework:
| Vanilla
| Vue
| > React
| Preact
| Lit
| Svelte
| Solid
| Qwik
| Angular
| Marko
| Others
—
回车
* Select a variant:
| TypeScript
| TypeScript + React Compiler
| TypeScript + SWC
| JavaScript
| JavaScript + React Compiler
| > JavaScript + SWC
| React Router v7 ↗
| TanStack Router ↗
| RedwoodSDK ↗
| RSC ↗
—
回车 (选择No)
* Use rolldown-vite (Experimental)?:
| Yes
| > No
—
回车 (选择No)
* Install with pnpm and start now?
| Yes / > No
—
```
**安装完项目,先不启动**。
**VScode打开项目。找到package.json文件,修改里面的 react和 react-dom为18.3.1版本,然后再 `pnpm i` 安装依赖**。
## JSX语法
**写法**
1. 只能有一个根元素
2. 标签中嵌入JS表达式时要用 `{}`
3. 循环绑定的元素需要设置key值
4. 给jsx设置类 `class`要写成`className` 行内样式 `style={{}}`
5. `label` 标签中的`for`要写成`htmlFor`
6. 所有标签必须形成闭合,成对闭合或者自闭合都可以
7. JSX支持多行(换行),如果需要换行,需使用 () 包裹,防止bug出现
**循环**必须加key,key的值不能重复。
**定义状态**,必须放到 state 里面。只有放到state里面的数据,在数据变化后,页面才会更新。
**更新数据**:
必须使用 this.setState({ 数据名: 新值, 数据名: 新值, ......... })
只能完整的、更新整个数据。如果是对象或数组,不能直接修改里面的某个属性。
**更新数据的步骤**:
1. 拷贝一份新的数据 `let newList = JSON.parse(JSON.stringify(this.state.list))`
2. 修改更新后的这份数据 `按照实际情况去填加、删除、修改....,去改newList`
3. 最后,使用 setState 整体改回去 `this.setState({ list: newList })`
受控组件:
- 表单元素,受到数据的控制。数据改变后,表单的状态才能改变(数据没有变化,表单元素不会变)
- 输入框 `value={}`
- 复选框 `checked={}`
- 单选框 `value={}`
- 下拉框 ``
- 一个表单项,加了上面的`value`或`checked`,必须配合一个 `onChange={() => {}}`
## 组件通信
### 父传子
**父组件**:给组件填加属性即可
```jsx
```
**子组件**:this.props.xxx 接收
```jsx
// Header.jsx 组件:
{this.props.title}
```
### 所谓的子传父
> 父组件写好方法,将方法传递给子组件。
**父组件**:
```jsx
del = (id) => {
// 完成删除功能
}
```
**子组件**:接收方法,点击后调用即可
```jsx
```
### 上下文传参
准备Ctx对象:
```jsx
import React from 'react'
const Ctx = React.createContext()
export default Ctx
```
父组件:
```jsx
import Ctx from '....'
render() {
return (
)
}
```
子组件:
```jsx
import Ctx from '...'
export default class List {
static contextType = Ctx // 关键行。加入这行,你的
render() {
return (
{this.context.title}
)
}
}
```
## 路由@6
步骤1:main.jsx 中,导入 BrowserRouter,然后将App包裹起来
```jsx
import { BrowserRouter } from 'react-router-dom'
createRoot(document.getElementById('root')).render(
,
)
```
步骤2:固定写到 App.jsx 中,定义基本的路由(嵌套格式是固定的:**Routes 里面 只能放 Route**)
```jsx
} />
} />
} />
} />
} />
```
步骤3:使用NavLink 或 Link 或 **组件库**进行跳转
步骤4:如果需要编程导航跳转以及获取参数,需要使用高阶组件套起来。高阶组件写法:
```jsx
import { useNavigate, useParams, useLocation } from 'react-router-dom'
function withRouter(Com) {
// 必须返回函数(这个函数就是下周要讲的函数组件)
return function NewComponent() {
// 必须在这里,这个位置。调用useXxx
const navigate = useNavigate() // 相当于是Vue中的 useRouter
const params = useParams() // 获取动态路由参数
const location = useLocation() // 相当于是Vue中的 useRoute
return (
<>
>
)
}
}
export default withRouter
```
步骤5:使用自己的withRouter将组件包裹即可使用 `this.props.navigate('/xxx')` 和 `this.props.params.id`
```jsx
import withRouter from '../hoc/withRouter'
class List extends Component {
render() {
return (
)
}
}
export default withRouter(List)
```
## 考题-案例
**可以提前安装项目,并且把需要的包安装好**。
```
安装项目
修改版本为 18.3.1
pnpm i
pnpm i react-vant
pnpm i @react-vant/icons
pnpm i react-router-dom@6
pnpm i @types/react-router-dom -D
```
准备好两个工具:
- addRouter 或 withRouter,每一个子组件,都套用他
- Ctx.jsx 文件
main.jsx里面:
- 导入 BrowserRouter ,将 `` 包裹起来
App.jsx中写路由、设计数据、使用上下文传递数据、增删改查方法都写到App,然后使用上下文向后传递。
后代页,在render函数的第一行输出 this ,查看一下数据、方法、路由信息,都在哪里????
- 上下文传递过来的:`this.context.list this.context.del() this.context.add()`
- 路由信息 `this.props.navigate('/xxx') this.props.params.id`
- 父传子,比如封装的Btns里面,获取父传子的数据 `this.props.arr this.props.active this.props.fn()`
## 第二周(ts)
hook 就是 useXxxx() 这样的一堆**函数**。因为有很多hook,所以叫做 hooks
比如vue学过 useRouter() useRoute()
从第二周开始,学习函数组件:
```jsx
// 类组件
class App extends Component {
render () {
return ssss
}
}
// 函数组件
function App () {
// 所有的hook,必须写到函数组件内部
const [a, setA] = useState(0)
return ssss
}
```
统一管理数据思想。增删改查所有代码放到一个文件中。
页面使用的时候,触发这些方法即可。(和Vuex非常像)(唯一的难点)
## useState
这个hook的作用用于定义状态(数据),并且提供一个专门用于更新状态的函数。
```jsx
const [age, setAge] = useState(18)
const [name, setName] = useState('zs')
const [height] = useState(180)
return setAge(20)}>{age}
```
## useMemo
作用:缓存属性。其实就是计算属性
```jsx
const total = useMemo(() => { /*return计算的结果*/ }, [依懒项, 依懒项, ....])
// 只有依懒项改变后,计算属性才会重新计算
const total = useMemo(() => {
return age + height
}, [age]) // 这个计算属性,依赖age的变化;只有age改变后,计算属性才会重新计算;height改变后,它不会重新计算
```
## 函数组件中的组件通信
### 父传子
父组件:
```jsx
```
子组件:
```jsx
function Home (props) {
// props ====== { 属性: xxx, 属性: yyy, 属性: 180 }
}
```
### 上下文传参
Ctx.jsx和之前一样
```jsx
import React from "react";
const Ctx = React.createContext()
export default Ctx
```
父组件:和之前一样
```jsx
import Ctx from '....'
```
子组件:
```jsx
import Ctx from '....'
const obj = useContext(Ctx)
// obj ==== { xx: 111, yy: 222 }
```
## useReducer使用逻辑

## 第二周需要安装的包
```
pnpm i react-vant
pnpm i react-router-dom@6
pnpm i @types/react-router-dom
pnpm i @react-vant/icons
```
## 第三周
### 安装的包:
```
安装 ts 版本项目:
pnpm i axios
pnpm i @reduxjs/toolkit
pnpm i react-redux
pnpm i react-router-dom@6
pnpm i @types/react-router-dom -D
pnpm install antd
pnpm install @ant-design/icons@5.x
```
先搭建页面+路由也可以。先把api写好,json-server启动也可以。
### utils/http.ts
```ts
import axios from "axios";
const instance = axios.create({
baseURL: 'http://localhost:3000'
})
instance.interceptors.request.use((config) => {
return config
}, (error) => {
return Promise.reject(error)
})
instance.interceptors.response.use(response => {
return response.data // 响应拦截器,一定要返回response.data
}, (error) => {
return Promise.reject(error)
})
export default instance
```
### 数据去考题中复制
略
### 根据数据写API(api/index.ts)
```tsx
import instance from "../utils/http";
// 两份数据;没份数据,需要查询、填加、修改、删除。所以一共需要8个API
// 4个商品接口
// 获取商品
export const getShopAPI = (params: {}) => {
return instance.get('/shoplist', { params })
}
// 填加商品
export const addShopAPI = (data) => {
return instance.post('/shoplist', data)
}
// 修改商品
export const updateShopAPI = (data) => {
return instance.put(`/shoplist/${data.id}`, data)
}
// 删除商品
export const deleteShopAPI = (id) => {
return instance.delete(`/shoplist/${id}`)
}
// 获取分类
export const getTypeAPI = (params: {}) => {
return instance.get('/typelist', { params })
}
// 填加分类
export const addTypeAPI = (data) => {
return instance.post('/typelist', data)
}
// 修改分类
export const updateTypeAPI = (data) => {
return instance.put(`/typelist/${data.id}`, data)
}
// 删除分类
export const deleteTypeAPI = (id) => {
return instance.delete(`/typelist/${id}`)
}
```
### 路由配置

### 菜单调整
```tsx
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
const Layout1: React.FC = () => {
// 路由跳转方法
const navigate = useNavigate()
// 获取地址栏的路由信息
const location = useLocation()
......
}