# react 移动端
**Repository Path**: baidizi/react---mobile
## Basic Information
- **Project Name**: react 移动端
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-10-19
- **Last Updated**: 2024-10-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# react 学习
## react 介绍








项目初始化
```
// 1.直接npx安装
//(npx是npm5.2+附带的package运行工具,和npm差不多版本,功能不太一样,不知道的话可以去搜一下)
npx create-react-app "项目名称"
// 2.先安装 create-react-app,在创建react项目
npm install -g create-react-app
npx create-react-app "项目名称"
cd my-app
npm start
```
## 页面初始化
构建完之后 只留一个index.js 和 App.js 这两个文件
index.js


App.vue

#### 推荐的一个官网
```
https://zh-hans.react.dev/learn/start-a-new-react-project
```
## jsx
### 介绍

用js编成的形式写html标签
### 本质上是扩展语法

可以在这个网站上体验一下 jsx 转换成 js
```
babeljs.io.repl
```

### jsx 基本使用


### jsx中实现列表渲染


### 条件渲染


### 复杂条件渲染


### 事件绑定

#### 原事件对象的参数

#### 传递自定义参数
这里采用的是函数回调的形式进行传参


注意这里直接绑定的话 相当于直接调用一次 是可以传递 但只能是一次回调 应该是和jsx的特性有关,被当成一个函数回调了
所以这里注意 使用 onClick的绑定函数的时候要不使用 函数的名字 要不就使用函数的定义
#### 同时传递事件对象参数和自定义参数

## react组件



## react Hook
### useState 数据驱动UI更新


#### 状态不可变

#### 修改对象状态

## 组件的样式处理


注意这里使用行内的写法的话 里面的属性要使用驼峰写法
## 实战评论
### 列表渲染(查)

这里通过 useState 接受数据 传递给ui上的然后的就是 map 渲染 出子元素
### 列表删除 (删)

这里使用fileter 过滤出新数组返回到 setCommentList中 (删)

### 渲染Tab+点击高亮实现 (增)

传统的 className 需要使用模板表达式

### 排序功能(改)

```
loadsh // 一个 封装了很多工具方法的函数
npm i lodash
```


## classnames 优化类名控制

```
npm i classnames
```
## 受控表单组件

## useRef


## 实战评论
### 发布评论

使用useRef获取e.taget.value 获取内容,将内容转到用回调函数 中使用useState获取传递 最后直接用发布将收集的内容放到评论列表
### ID处理和时间处理

```
npm i uuid
import { v4 as uuidv4 } from 'uuid'
uuidv4()
```
```
npm install dayjs
const dayjs = require('dayjs')
dayjs().format()
// 样例
dayjs(new Date()).format('MM-DD hh:mm')
dayjs('2019-05-25').format(‘DD/MM/YYYY’)
```
### 清空内容和重新聚焦


## 组件通讯

### 父传子


### prop 说明

### 父传子-特殊的prop children (类似插槽)

### 子传父
同过传递函数 ,然后子组件用传递过来的函数回调

### 状态提升
将变量传给共同的父组件

### 使用context

## useEffect

### 基础用法
就像像是可以用来模拟生命周期里面的onMounted


```
import { useEffect } from "react";
const URL = "http://geek.itheima.net/v1_0/channels";
function App() {
useEffect(() => {
async function geList() {
const res = await fetch(URL);
const data = await res.json();
console.log(data);
}
geList();
}, []);
return
;
}
export default App;
```
### 高级用法

第一种 onMount + onLoad
第二种 onMount
第三种 onMount+ watch
### 清除副作用


写一个return函数即可 相当于组件卸载了的时候去执行一下return里面的代码

## 自定义hooks

就用来封装一下逻辑 方便复用 为什么这个叫自定义hook呢?不叫自定义函数呢?因为这和下面的react hook的规则有关
如果没有使用react hook 的话就可以使用自定义函数 不然都是自定义hook


## react hook的使用规则

注意这个hooks是说的事use开头的
## 实战 评论列表的优化


### mock 服务
```
npm install json-server
```

创建 json-server 需要的dp.json文件
创建命令 创建数据

```
```
然后加入命令 启动服务
前端则注意安装
```
npm i axios
```

### 复杂组件

这里直接封装成一个item组件 然后使用组件传值即可

这里就是封装完之后的结果
## redux

### 简单实现

```
Redux Counter Example
-
0
+
```

### 在react中实现


vite创建项目可以用
```
npm create vite
```

### 使用


注册一个redux模块

#### 使用方式




#### 传参数


#### 异步使用







#### 调试工具

### 综合实战


#### 这里使用模板快速初始化 然后实现crud功能即可
模板在压缩包
启动start 启动server即可
#### 分类和商品列表渲染实现


这里封装一下redux的同步任务和异步任务
```
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const foodsStore = createSlice({
name:'foods',
initialState:{
foodsList:[]
},
reducers:{
setFoodsList(state,action){
state.foodsList = action.payload
}
}
})
const {setFoodsList } = foodsStore.actions
export const fetchFoodlist = ()=>{
return async (dispacth)=>{
const res = await axios.get('http://localhost:3004/takeaway')
dispacth(setFoodsList(res.data))
}
}
const reducer = foodsStore.reducer
export default reducer
```
在redux中注册这个模块
```
import foodsReducer from './modules/takeaway'
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({
reducer:{
foods:foodsReducer
}
})
export default store
```
在index中注入模块
```
import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
// 注入store
import { Provider } from 'react-redux'
import store from './store'
const root = createRoot(document.getElementById('root'))
root.render(
)
```
最后在需要的地方引入即可
```
import NavBar from './components/NavBar'
import Menu from './components/Menu'
import Cart from './components/Cart'
import FoodsCategory from './components/FoodsCategory'
import './App.scss'
import { useDispatch, useSelector } from 'react-redux'
import { useEffect } from 'react'
import { fetchFoodlist } from './store/modules/takeaway'
const App = () => {
// 触发 action 执行
// 1.useDispatch -> dispatch 2.actionCreater 导入进来 3.useEffect
const dispacth = useDispatch()
useEffect(()=>{
dispacth(fetchFoodlist())
},[dispacth])
const {foodsList} = useSelector(state=>state.foods)
return (
{/* 导航 */}
{/* 内容 */}
{/* 外卖商品列表 */}
{foodsList.map(item => {
return (
)
})}
{/* 购物车 */}
)
}
export default App
```
#### 点击分类的交叉实现

这里就比较简单直接存入一个状态然后直接去调用即可
定义
```
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const foodsStore = createSlice({
name:'foods',
initialState:{
foodsList:[]
},
activeIndex:0,
reducers:{
setFoodsList(state,action){
state.foodsList = action.payload
},
changeActiveIndex(state,action){
state.activeIndex = action.payload
}
},
})
const {setFoodsList,changeActiveIndex } = foodsStore.actions
const fetchFoodlist = ()=>{
return async (dispacth)=>{
const res = await axios.get('http://localhost:3004/takeaway')
dispacth(setFoodsList(res.data))
}
}
const reducer = foodsStore.reducer
export {fetchFoodlist,changeActiveIndex}
export default reducer
```
使用
```
import classNames from 'classnames'
import './index.scss'
import { useDispatch, useSelector } from 'react-redux'
import { changeActiveIndex } from '../../store/modules/takeaway'
const Menu = () => {
const {foodsList,activeIndex} = useSelector(state=>state.foods)
const dispacth = useDispatch()
const menus = foodsList.map(item => ({ tag: item.tag, name: item.name }))
return (
)
}
export default Menu
```
#### 控制列表 条件渲染列表

```
import NavBar from './components/NavBar'
import Menu from './components/Menu'
import Cart from './components/Cart'
import FoodsCategory from './components/FoodsCategory'
import './App.scss'
import { useDispatch, useSelector } from 'react-redux'
import { useEffect } from 'react'
import { fetchFoodlist } from './store/modules/takeaway'
const App = () => {
// 触发 action 执行
// 1.useDispatch -> dispatch 2.actionCreater 导入进来 3.useEffect
const dispacth = useDispatch()
useEffect(()=>{
dispacth(fetchFoodlist())
},[dispacth])
const {foodsList,activeIndex} = useSelector(state=>state.foods)
return (
{/* 导航 */}
{/* 内容 */}
{/* 外卖商品列表 */}
{foodsList.map((item,index) => {
return (
activeIndex===index &&
)
})}
{/* 购物车 */}
)
}
export default App
```
#### 添加购物车


这里使用redux修改存储状态即可
#### 购物车展示


#### 购物车列表展示


#### 购物车展示和隐藏


##### 备注对于redux
###### 在定义的时候
可以通过createSlice 将state 和 同步修改状态封装在里面
但是异步状态智能封装在外面
因为 reducer设计之初就是只改变状态不产生其他副作用(这里没有vue的action强)
```
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const foodsStore = createSlice({
name:'foods',
initialState:{
foodsList:[],
},
reducers:{
setFoodsList(state,action){
state.foodsList = action.payload
},
},
})
const {setFoodsList } = foodsStore.actions
const fetchFoodlist = ()=>{
return async (dispacth)=>{
const res = await axios.get('http://localhost:3004/takeaway')
dispacth(setFoodsList(res.data))
}
}
const reducer = foodsStore.reducer
export {fetchFoodlist}
export default reducer
```
###### 引用的时候
这里状态引用可以使用 useSelect 将state状态解构出来
但是其他的同步函数,和异步函数 需要手动import 出来 然后再使用 useDisoatch()返回的dispatch调用才可以(建议将dispatch和import封装在一起,方便调用)
```
import { changeActiveIndex } from '../../store/modules/takeaway'
const {foodsList} = useSelector(state=>state.foods)
const dispacth = useDispatch()
...onClick={()=>{dispacth(changeActiveIndex(index))}}
```
## React-router
### 基础使用



```
import React from 'react'
import { createRoot } from 'react-dom/client'
import { createBrowserRouter,RouterProvider } from 'react-router-dom'
// 定义Router
const router = createBrowserRouter([
{
path:"/",
element:Hello WOrld
},
{
path:"/app",
element:Hello app
},
])
const root = createRoot(document.getElementById('root'))
root.render(
)
```
### 封装一下


### 路由导航

#### 声明式导航


#### 编程式导航


### 路由传参




### 嵌套路由


为子路由渲染出口
### 默认路由

### 404

### 两种路由模式

createHashRouter 就是有井号的那个 /#/
### 实战


#### 路径配置



#### mock



#### 初始化
















navigate 重定向组件








懒加载





不打包资源 直接从最近的服务器获取即可 然后直接在index中 script引入

## 待定
## useReducer




##
## useMemo
缓存计算结果 只有特定的状态变了才重新执行函数





## React.memo
### 基础使用



原来的每次执行count 都会重新渲染son组件
现在需要将其用memo将其包裹起来


### 机制

浅拷贝比较
注意当处于引用状态的时候 父组件的每次渲染都会让引用地址发生变化 也就是缓存不了


这里的处理方式事直接缓存一下这个数据 通过useMemu

## useCallback


## forwardRef



## useInpetactiveHandle





# 了解类组件(用来维护老项目)
## 类组件



## 类组件生命周期


## 父子组件通信





# Zustand
## 同步状态




## 异步状态


## 模块化



# React 和 Ts



## useState 和 TS


## 泛型


## 空值


## props 与 TS


## props 与 ts 中children

## props 与 函数

## useRef 与 ts


# error lens
一款好用的插件 可以给代码一些错误提示

# 实战













在使用的时候会有类型推断


## 逻辑和视图的分离










接口管理工具的生成ts代码
