react基础+pc项目
-
技术栈为:React + Hook + React-router-v6 + Mobx + AntD
-
React 基础讲义: https://www.yuque.com/fechaichai/qeamqf/xbai87
-
ReactPc 项目讲义: https://www.yuque.com/fechaichai/tzzlh1
-
React 英文文档( https://reactjs.org/ )
-
React 中文文档 ( https://zh-hans.reactjs.org/ )
-
React 新文档 ( https://beta.reactjs.org/ )(开发中....)
-
安装 npx create-react-app demo
-
JSX 条件渲染
-
可以使用三元运算符或者逻辑&&运算
-
原则: 模板中的逻辑尽量保持精简
-
复杂的多分支的逻辑收敛为一个函数 通过一个专门的函数来写分支逻辑,模板中只负责调用
JSX 注意事项
add
- class->className
- for -> htmlFor
- <></> 幽灵节点
- JSX 换行需要()包裹
表单组件
-
受控组件: 被 react 的状态控制的组件
-
input 框自己的状态被 React 组件状态控制
-
非受控组件
-
手动操作 dom 的方式获取文本的值
-
createRef
-
myRef.current.value
-
生成独一无二的 id 可以使用 uuid 包 yarn add uuid
import { v4 as uuid } from "uuid"
uuid() // 得到一个独一无二的id
- 父传子 props 函数
- 子传父:子组件调用父组件传递过来的函数,并且把想要传递的数据当成函数的实参
兄弟组件通信
-
通过状态提升机制,利用共同的父组件实现兄弟通信
-
组件通信-Context 实现跨组件传递数据
-
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法
-
Provider 提供者 Consumer 消费者
-
实现步骤
-
1、创建 Context 对象,导出 Provider 和 Consumer 对象
-
const { Provider,Consumer } = createContext() -
2、使用 Provider 包裹跟组件提供数据
-
3、需要用到数据的组件使用 Consumer 包裹获取数据
{value => /基于context值进行渲染/}
children 属性
- 表示该组件的子节点,只有组件内部有子节点,props 中就有该属性
- children 可以是
- 1、普通文本
- 2、普通标签元素
- 3、函数
- 4、JSX
props 类型校验
-
实现步骤
-
1、安装属性校验包:yarn add prop-types
-
2、导入 prop-types 包
-
3、使用组件名.propTypes = {} 给组件添加校验规则
import PropTypes from "prop-types";
const list = props => {
const arr = props.colors
const lis = arr.map((item,index) => - {item.name} )
return
- {lis}
}
list.propTypes = {
colors: PropTypes.array
}
props 校验-规则说明
-
四种常见结构
-
1、 常见类型:array、bool、func、number、object、string
-
2、React 元素类型:element
-
3、必填项:isRequired
-
4、特定的结构对象:shape({})
// 常见类型
optionalFunc: PropTypes.func
// 必选
requiredFunc: PropTypes.func.isRequired
// 特定结构的对象
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
prop 默认值
-
1、函数组件 使用 defaultProps
// 设置默认值
xxx.defaultProps = {
pageSize: 10}
-
使用函数参数默认值(推荐)
-
注意:函数组件,新的 react 已经不再推荐 defaultProps 来添加默认值,而是推荐函数参数默认值来实现
-
区别:第一种在用的时候组件内部已经有了 pageSize 这个 prop 第二种只有传递的时候组件内部才有了 prop
function List({pageSize = 10}) {
return(
)}
-
2、类组件 defaultProps
xxx.defaultProps = {
pageSize: 10
} -
使用类静态属性声明
static defaultProps = {
pageSize: 10
}
生命周期
- 只有类组件才有生命周期(类组件实例化 函数组件不需要实例化)
生命周期-挂载阶段
-
constructor ---> render ---> componentDidMount
-
1、钩子函数:constructor;触发时机: 创建组件时,最先执行,初始化的时候只执行一次;作用:1.初始化 state 2.创建 Ref 3.使用 bind 解决 this 指向问题等
-
2、钩子函数:render;触发时机:每次组件渲染都会触发;作用:渲染 UI(注意:不能再里面调用 setState())
-
3、钩子函数:componentDidMount ;触发时机: 组件挂载(完成 DOM 渲染)后执行,初始化的时候执行一次;作用:1.发送网络请求 2.DOM 操作
生命周期-更新阶段
-
render ---> conponentDidUpdate
-
1、钩子函数:render; 触发时机:每次组件渲染都会触发;作用: 渲染 UI(与挂载阶段是同一个 render)
-
2、钩子函数:componentDidUpdate;触发时机:组件更新后(DOM 渲染完毕);作用:DOM 操作,可以获取到更新后的 DOM 内容,不用直接调用 setState
生命周期-卸载阶段
-
componentWillUnmount
-
1、钩子函数:componentWillUnmount;触发时机:组件卸载(从页面中消失);作用:执行清理工作(比如:清理定时器等)
Hooks 概念理解
1、什么是 hooks
-
Hooks 的本质:一套能够使函数组件更强大,更灵活的“钩子”
-
React 的设计理念
UI = f(data) -
useState
-
useEffect
-
自定义 hook
-
自定义一个 hook 函数,实现获取滚动距离的 y
import { useState } from "react"
export function useWindowScroll() {
const [y,setY] = useState(0);
window.addEventListener('scroll',() => {
const h = document.documentElement.scrollTop
setY(h)
})
return [y]}
// 引入
import { useWindowScroll } from "./xxx.js"
const [y] = useWindowScroll() -
自定义 hook 函数,可以自动同步到本地 LocalStorage
-
message 可以通过自定义传入默认初始值
-
每次修改 message 数据的时候,都会自动往本地同步一份
import { useEffect, useState } from "react"
export function useLocalStorage(key,defaultValue) {
const [message,setMessage] = useState(defaultValue)
// 每次只要message变化,就会自动同步到本地ls
useEffect(() =>{
window.localStorage.setItem(key,message)
},[message,key])
return [message,setMessage]
}
// 引用
import { useLocalStorage } from "xxx"
const [message,setMessage] = useLocalStorage('hook-key','测试')
setTimeout(() => {
setMessage('cp)
},5000) -
useState -回调函数的参数
-
const [name,setName ] = useState(() => { // 编写计算逻辑 return '计算之后的初始值'}) -
useState(() = > {})
useEffect - 清理副作用
useEffect(() => {
console.log('副作用函数执行了')
// 副作用函数的执行时机为:在下一次副作用函数执行之前执行
return() => {
console.log('清理副作用的函数执行了')
// 在这里写清理副作用的代码
}
})
-
案例
function Test() {
useEffect(() => {
let timer = setInterval(() => {
console.log('定时器执行了')
},1000)
return () => {
// 清理的动作
clearInterval(timer)
}
},[])
}
-
发送请求
useEffect(() => {
async = function fetchData() {
const res = await axios.get('xxx')
console.log(res)
}
fetchData();
},[])
useContext
-
实现步骤
-
1、使用 createContext 创建 Context 对象
-
2、在顶层组件通过 Provider 提供数据
-
3、在底层组件通过 useContext 函数获取数据
-
代码实现
import { createContext, useContext } from "react"
const Context = createContext();
function Foo() {
returnFoo
}
function Bar() {
// 底层组件通过useContext函数获取数据
const name = useContext(Context);
returnBar {name}
}
function App() {
return (
// 顶层组件通过Provider提供数据
<Context.Provider value={'this is name'}>
</Context.Provider>
)
} -
context 如果要传递的数据,只需要在整个应用初始化的时候传递一次就可以,就可以选择在当前文件(index.js)里做数据提供
- 如果 context 需要传递数据并且将来还需要在对数据做修改底层组件也需要,跟着一起变,需要写到 app.js
- 如果提供数据是静态不变-index.js 包裹
- 如果提供数据需要编号-app.js 可以发便更改数据
React Router V6
1、基础使用
- 安装 yarn add react-router-dom@6
-
app.jsx
// 引入必要的内置组件
import { BrowserRouter, Routes, Route, Link } from "react-router-dom"
// 准备两个路由组件
const Home = () =>this is home
const Ablut = () =>this is about
// 进行路由配置
function App() {
return(
// BrowserRouter声明当前要用一个非hash模式的路由
// Link指定跳转的组件,to用来配置路由地址
首页
关于
// Routes路由出口 路由对应的组件会在这里进行渲染
// Route指定路径和组件的对应关系,path代表路径 element代表组件成对出现path -> element
<Route path="/" element={}>
// /about 可以省略/ /about =about
<Route path="/about" element={}>
)
}
2、核心组件说明
(1)、核心组件-BrowerRouter
- 作用:包裹整个应用,一个 React 应用只需要使用一次
- 两种常见 Router: HashRouter 和 BrowserRouter
- HashRouter: 使用 URL 的哈希值实现(http://localhose:3000/#/first)
- BrowserRouter: 使用 H5 的 history.pushState API 实现(http://localhose:3000/first)
(2)、核心组件-Link
-
作用: 用于指定导航链接,完成路由跳转
-
语法说明:组件通过 to 属性指定路由地址,最终会渲染为 a 链接元素
-
<Link to="/path" >页面一</Link>
(3)、核心组件- Routes
-
作用:提供一个路由出口,满足条件的路由组件会渲染到组件内部
// 满足条件的路由组件会渲染到这里
(4)、核心组件- Route
- 作用:用于指定导航链接、完成路由匹配
- 语法说明:path 属性指定匹配的路径地址,element 属性指定要渲染的组件
<Route path="/about" element={<Ablut />}/>- 说明: 当 url 路径为
/about时,会渲染<About />组件
3、编程式导航(跳转与参数)
(1)、编程式导航-跳转
-
作用:通过 js 编程的方式进行路由页面跳转,比如从登录页跳转到关于页
-
语法说明:
-
1、导入 useNavigate 钩子函数
-
2、执行钩子函数得到跳转函数
-
3、执行跳转函数完成跳转
-
注意: 如果在跳转时不想加历史记录,可以添加额外参数 replace 为 true
navigate('/about', { replace: true } )import { useNavigate } from "react-router-dom"
const Home = () => {
//执行函数
const navigate = useNavigate();
return (
Home
<button onClick={() => navigate('/about')}>跳转关于页
)
}
export default Home
(2)、编程式导航-跳转携带参数
-
1、searchParams 传参
-
传参
-
navigate(''/about?id=1001) -
取参
-
let [params] = useSearchParams();let id = params.get('id') -
params 是一个对象,对象里有一个 get 的方法,用来获取对应的参数,把参数的名称作为 get 的实参传过来
-
2、params 传参
-
路由传参
-
navigate('/about/1001') -
路由取参
-
let params = useParams();let id = params.id
4、嵌套路由
-
实现步骤
-
1、App.js 中定义嵌套路由声明
-
2、Layout 组件内部通过
指定二级路由出口 -
App.jsx
<Route path="/" element={}>
<Route path="board" element={}>
<Route path="article" element={}>
-
Layout.jsximport { Outlet } from "react-router-dom"
const Layout = () => {
return(
layout页面
// 二级路由的path等于一级path+二级path
board
article
// 二级路由出口
)
}
export default Layout;
默认二级路由
- 场景:应用首次渲染完毕就需要显示的二级路由
- 实现步骤
- 1、给默认二级路由标记 index 属性
- 把原本的路径 path 属性去掉
-
App.jsx
<Route path="/" element={}>
<Route index element={}>
<Route path="article" element={}>
-
Layout.jsximport { Outlet } from "react-router-dom"
const Layout = () => {
return(
layout页面
// 二级路由的path等于一级path+二级path
board
article
// 二级路由出口
)
}
export default Layout;
5、404 页配置
-
场景:当 url 的路径在整个路由配置中都找不到对应的 path,使用 404 兜底组件进行渲染
-
1- 准备一个 NotFound 组件
-
NotFound.jsxconst NotFound = () => {
returnthis is NotFound
}export default NotFound
-
App.jsx
<Route path="/" element={}>
<Route index element={} />
<Route path="article" element={} />
<Route path="*" element={}>
Mobx
- 一个可以和 React 良好配合的集中状态管理工具,mobx 和 react 的关系,相当于 vuex 和 vue
- 同类工具还有:
- redux
- dva
- recoil
Mobx 环境配置
- Mobx 来做响应式数据建模
- 1、使用 create-react-app 初始化 react 项目
npx create-react-app mobx-react-app- 2、安装 mobx 和 mobx-react-lite
yarn add mobx mobx-react-lite
Mobx 第一个 store
1、初始化 mobx
-
初始化步骤
-
1、定义数据状态(state)
-
2、在构造器中实现数据响应式处理
-
3、定义 action 函数(修改数据)
-
4、实例化 store 并导出
-
counterStore.jsimport { makeAutoObservable } from "mobx"
class CounterStore {
count = 0 // 定义数据
constructor() {
makeAutoObservable(this) // 响应式处理
}
// 定义修改数据的方法
addCount = () => {
// 定义action函数
this.count++
}
}
// 实例化
const counterStore = new CounterStore();
export default counterStore
2、React 使用 store
- 实现步骤
- 1、导入 store 实例
- 2、使用 store 中的数据
- 3、修改 store 中的数据
- 4、让组件视图响应数据变化
-
App.js// 导入counterStore
import conuterStore from "./store"
// 导入observer方法
import { observer } from "mobx-react-lite"
function App() {
return(
<button onClick={() => conuterStore.addCount()}>{conuterStore.count}
)
}
// 包裹组件让视图响应数据变化
export default observer(App)
3、computed 计算属性
- 实现步骤
- 1、声明一个存在的数据
- 2、定义 get 计算属性
- 3、在 makeAutoObservable 方法中标记
-
counterStore.jsimport { computed, makeAutoObservable } from 'mobx'
class CounterStore {
list = [1, 2, 3, 4, 5, 6]
constructor() {
makeAutoObservable(this, {
filterList: computed
})
}
// 修改原数组
changeList = () => {
this.list.push(7, 8, 9)
}
// 定义计算属性
get filterList () {
return this.list.filter(item => item > 4)
}
}const counter = new CounterStore()
export default counter
-
App.js// 导入counterStore
import counterStore from './store'
// 导入observer方法
import { observer } from 'mobx-react-lite'
function App() {
return (
{/* 原数组 /}
{JSON.stringify(counterStore.list)}
{/ 计算属性 */}
{JSON.stringify(counterStore.filterList)}
<button onClick={() => counterStore.changeList()}>change list
)
}
// 包裹组件让视图响应数据变化
export default observer(App)
4、模块化
-
实现步骤
-
1、拆分模块 js 文件,每个模块中定义自己独立的 state/action
-
2、在 store/index.js 中导入拆分之后的模块,进行模块组合
-
3、利用 React 的 context 的机制导出统一的 useStore 方法,给业务组件使用
-
1、定义 task 模块
-
store/taskStore.jsimport { makeAutoObservable } from "mobx"
class TaskStore{
taskList = []
constructor() {
makeAutoObservable(this)
}
addTask() {
this.taskList.push('vue','react')
}
}
const task = new TaskStore()
export default tash
-
2、定义 counterStore
import { makeAutoObservable } from "mobx"
class CounterStore{
count = 0;
list = [1,2,3,4,5,6]
constructor() {
makeAutoObservable(this)
}
addCount = () => {
this.count++
}
changeList = () => {
this.list.push(7,8,9)
}
get filterList () {
return this.list.filter(item => item >4 )
}
}
const counter = new CounterStore();
export default counter -
3、组合模块导出统一方法
-
store/index.jsimport React from "react"
import counter from "./counterStore"
import task from "./taskStore"
class RootStore{
constructor() {
this.counterStore = counter
this.taskStore = task
}
}
const rootStore = new RootStore()
const context = React.createContext(rootStore)
const useStore = () => React.useContext(context)
export -
4、组件使用模块中的数据
import { observer } from "mobx-react-lite"
// 导入方法
import { useStore } from "./store"
function App() {
// 得到store
const store = useStore();
return(
<button onClick={() => store.counterStore.addCount()}>{store.counterStore.count}
)
}
// 包裹组件让视图响应数据变化
export default observer(App)
Mobx 基础使用-总结
- 1、初始化 mobx 的过程是怎样的?
- 声明数据 ->响应式处理 ->定义 action 函数 ->实例化导出
- 2、mobx 如何配合 react,需要依赖什么包?
- mobx-react-lite 作为链接包,导出 observer 方法,包裹组件(只能和函数组件配合)
- 3、模块化解决了什么问题?
- 维护性问题
- 4、如何实现 mobx 的模块化?
- 按照功能拆分 store 模块,根模块中组合子模块,利用 context 机制依赖注入
react-uuid 创建一个独一无二的 id
- import uuid from "react-uuid"
Mobx 和 React 职责划分
Store
- 1、业务状态数据
- 2、业务状态操作逻辑
React
-
1、渲染业务数据
-
2、UI 临时状态维护
-
3、事件触发,调用 Mobx
-
富文本编辑器 react-quill
pc 端项目
1、项目技术
-
React 官方脚手架 create-react-app
-
react hooks
-
状态管理:mobx
-
UI 组件库:antd v4
-
ajax 请求库:axios
-
路由:react-router-dom 以及 history
-
富文本编辑器:react-quill
-
CSS 预编译器:sass
body {
margin: 0;
}root {
height: 100%;
}
2、实现步骤
- 1、使用 create-react-app 生成项目 npx create-react-app react-demo-pc
- 2、进入跟目录 cd react-demo-pc
- 3、启动项目 yarn start
3、 使用 gitee 管理项目
- 1、在项目根目录打开终端,并初始化 git 仓库(如果已经有了 git 仓库,无需重复该步),命令:git init
- 2、添加项目内容到暂存区: git add .
- 3、提交项目内容到仓库区: git commit -m '项目初始化'
- 4、添加 remote 仓库地址: git remote add origin [gitee 仓库地址]
- 5、将项目内容推送到 gitee: git push origin master -u // -u 可不传
4、使用 scss 预处理器
- 1、安装解析 sass 的包: yarn add sass -D
- 创建全局样式文件: index.scss
5、配置基础路由
-
1、安装路由:yarn add react-router-dom
-
2、在 page 目录中创建两个文件夹: Login、Layout
-
3、分别在两个目录中创建 index.js 文件,并创建一个简单的组件后导出
-
4、在 App 组件中,导入路由组件以及两个页面的组件
-
5、配置 Login 和 Layout 的路由规则
-
page/Login/index.jsconst Login = () => {
returnlogin
}
export default Login
-
pages/Layout/index.jsconst Layout = () => {
returnlayout
}
export default Layout -
app.js// 导入路由
import { BrowserRouter, Route, Routes } from 'react-router-dom'// 导入页面组件
import Login from './pages/Login'
import Layout from './pages/Layout'// 配置路由规则
function App() {
return (
<Route path="/" element={}/>
<Route path="/login" element={}/>
)
}export default App
6、组件库 antd 使用
-
1、安装 antd 组件库: yarn add antd
-
2、全局导入 antd 组件库的样式
-
3、导入 Button 组件
-
4、在 Login 页面渲染 Button 组件进行测试
-
src/index.js// 先导入 antd 样式文件
// https://github.com/ant-design/ant-design/issues/33327
import 'antd/dist/antd.min.css'
// 再导入全局样式文件,防止样式覆盖!
import './index.css'
-
pages/Login/index.jsimport { Button } from 'antd'
const Login = () => (
)
7、配置别名路径
- 自定义 CRA 的默认配置:https://ant.design/docs/react/use-with-create-react-app-cn#高级配置
- craco 配置文档:https://github.com/gsoft-inc/craco/blob/master/packages/craco/README.md#configuration
-
CRA 将所有工程化配置,都隐藏在了 react-scripts 包中,所以项目中看不到任何配置信息
-
如果要修改 CRA 的默认配置,有以下几种方案:
-
a. 通过第三方库来修改,比如,@craco/craco (推荐)
-
b. 通过执行 yarn eject 命令,释放 react-scripts 中的所有配置到项目中
-
实现步骤
-
1、安装修改 CRA 配置的包:yarn add -D @craco/craco
-
2、在项目根目录中创建 craco 的配置文件:
craco.config.js,并在配置文件中配置路径别名 -
3、修改
package.json中的脚本命令 -
4、在代码中,就可以通过
@来表示 src 目录的绝对路径 -
5、重启项目,让配置生效
-
craco.config.jsconst path = require('path')
module.exports = {
// webpack 配置
webpack: {
// 配置别名
alias: {
// 约定:使用 @ 表示 src 文件所在路径
'@': path.resolve(__dirname, 'src')
}
}
} -
package.json// 将 start/build/test 三个命令修改为 craco 方式
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}
8、@别名路径提示
-
1、在项目根目录创建
jsconfig.json配置文件 -
2、在配置文件中添加一下配置
-
jsconfig.json{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/": ["src/"]
}
}
} -
vscode 会自动读取 jsconfig.json 中的配置,让 vscode 知道@就是 src 目录
9、路由鉴权实现
-
实现步骤
-
1、在 components 目录中,创建 AuthRoute/index.js 文件
-
2、判断是否登录
-
3、登录时,直接渲染相应页面组件
-
4、未登录时,重定向到登录页面
-
5、将需要鉴权的页面路由配置,替换为 AuthRoute 组件渲染
-
components/AuthRoute/index.js
// 1、判断 token 是否存在
// 2、如果存在 直接正常渲染
// 3、如果不存在 重定向到登录路由
// 高阶组件:把一个组件当初另外一个组件的参数传入 然后通过一定的判断 返回新的组件
import { getToken } from "@/utils"
import { Naviagate } from "react-router-dom"
function AuthRoute({children}) {
const isToken = getToken();
if(isToken) {
return <>{children}</>
}else {
return
}
}
//
// 登录:<>
// 非登录:
export { AuthRoute }
-
src/app.jsimport { Router, Routes,Route } from "react-router-dom"
import { AuthRoute } from "@/components/AuthRoute"
import Layout from "@/page/Layout"
import Login from "@/pages/Login"function App() {
return(
/需要鉴权的路由/
<Route path="/*" element={ }/>
/**不需要鉴权的路由/
<Route path="/login" element={} />
)
}
-
如何在 react 获取 dom -> useRef
-
在什么地方获取 dom 节点 -> useEffect
// 获取频道列表
const [ channels,setChannels] = useState();
useEffect(() => {
async function featchChannels() {
const res = await http.get('/xxx')
setChannels(res.data.channels)
}
featchChannels();
}.[])
-
如果异步请求函数需要依赖一些数据的变化而重新执行, 推荐把它写到内部
-
统一不抽离函数到外面 只有涉及到异步请求的函数 都放到 useEffect 内部
-
本质区别:写到外面每次组件更新都会重新进行函数初始化 这本身就是一次性性能消耗,
-
而写到 useEffect 中 只会在依赖项发生变化的时候 函数才会进行重新初始化
-
避免性能损失
// 文章列表管理 统一管理数据 将来修改给setList传对象
const [list, setList ] = useState({
list: [], // 文章列表
count: 0, // 文章数量
})
// 文章参数管理
const [ params, setParams ] = useState({
page: 1,
per_page: 10
})
富文本编辑器
-
实现步骤
-
1、安装富文本编辑器:yarn add react-quill
-
2、导入富文本编辑器组件以及样式文件
-
3、渲染富文本编辑器组件
-
4、通过 Form 组件的 initialValues 为富文本编辑器设置初始值,否则会报错
-
5、调整富文本编辑器的样式
import React, { useState } from 'react';
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
function MyComponent() {
const [value, setValue] = useState('');
return;
}
暂存图片列表实现
问题描述
- 如果当前为三图模式,已经完成了上传,选择单图只显示一张,再切换到三图继续显示三张,该如何实现?
实现思路
- 在上传完毕之后通过 ref 存储所有图片,需要几张就显示几张,其实也就是把 ref 当仓库,用多少拿多少
实现步骤
-
1、通过 useRef 创建一个暂存仓库,在上传完毕图片的时候把图片列表存入
-
2、如果是单图模式,就从仓库里取第一张图,以数组的形式存入 fileList
-
3、如果是三图模式,就把仓库里所有的图片,以数组的形式存入 fileList
const Publish = () => {
// 1、声明一个暂存仓库
const fileListRef = useRef([])
// 2、上传图片时,将所有图片存储到ref中
const onUploadChange = info => {
fileListRef.current = imgUrls
}
// 3、切换图片类型
const changeType = e => {
// 使用原始数据作为判断条件
const count = e.target.value
setMaxCount(count)
if(count === 1) {
// 单图,只展示第一张
const firstImg = fileListRef.current[0]
setFileList(!firstImg ? [] : [firstImg])
}else if(count === 3) {
// 三图展示所有图片
setFileList(fileListRef.current)
}
}
}
- 获取传参的 id
?id=xxx - const [ params ] = useSearchParams();
- const id = params.get('id')
路由懒加载
使用步骤
-
1、在 App 组件中,导入 Suspense 组件
-
2、在路由 Router 内部,使用 Suspense 组件包裹组件内容
-
3、为 Suspense 组件提供 fallback 属性,指定 loading 占位内容
-
4、导入 lazy 函数,并修改为懒加载方式导入路由组件
import { Routes, Route } from 'react-router-dom'
import { HistoryRouter, history } from './utils/history'
import { AuthRoute } from './components/AuthRoute'// 导入必要组件
import { lazy, Suspense } from 'react'
// 按需导入路由组件
const Login = lazy(() => import('./pages/Login'))
const Layout = lazy(() => import('./pages/Layout'))
const Home = lazy(() => import('./pages/Home'))
const Article = lazy(() => import('./pages/Article'))
const Publish = lazy(() => import('./pages/Publish'))function App () {
return (
<Suspense
fallback={
<div
style={{
textAlign: 'center',
marginTop: 200
}}
>
loading...
}
>
{/* 需要鉴权的路由 /}
<Route path="/" element={
}>
{/ 二级路由默认页面 /}
<Route index element={} />
<Route path="article" element={} />
<Route path="publish" element={} /> 不需要鉴权的路由 */}
{/
<Route path='/login' element={} />
)
}
export default App

浙公网安备 33010602011771号