李金帅
能将喜欢的东西留在身边,这就是我努力的意义。

React开发流程小记

2023-04 React react-router-dom react-redux Redux Toolkit axios
Word count: 3k | Reading time: 14min

创建项目

1
2
3
4
5
6
7
8
9
10
11
npx create-react-app xxx

// 创建成功后可安装 axios 对请求进行二次封装
npm i axios
// 根据需求进行配置 官网 https://axios-http.com/zh/docs/intro

// 可安装 Redux Toolkit 高效的 Redux 开发工具
npm install @reduxjs/toolkit react-redux
// 根据需求进行配置 官网 https://cn.redux.js.org/

........ 更多配置自行构建

注意:在项目中需要挂载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 导入react核心模块包,导入react-dom,他提供了和dom相关的功能,比如渲染dom节点,操作dom
import React from 'react';
import ReactDOM from 'react-dom/client';
// 导入全局样式
import './index.css';
// 导入根组件
import App from './App';
// 1、导入并挂载路由
// HashRouter vue中的hash模式
// BrowserRouter vue中的history模式
import { HashRouter, BrowserRouter } from 'react-router-dom';

// 在id为root的容器里面渲染根组件App
const root = ReactDOM.createRoot(document.getElementById('root'));
// React.StrictMode 组件设置严格模式,语法要求严格,控制编码习惯的
root.render(
<HashRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</HashRouter>
);

注意: React.StrictMode 开发状态下的严格模式
StrictMode 是一个用来检查项目中潜在问题的工具。StrictMode 不会渲染任何可见的 UI,它为其后代元素触发额外的检查和警告。

1
2
3
4
5
6
7
8
9
严格模式检查仅在开发模式下运行;它们不会影响生产构建。

StrictMode 目前有助于:

1、识别不安全的生命周期;
2、关于使用过时字符串 ref API 的警告;
3、关于使用废弃的 findDOMNode 方法的警告;
4、检测意外的副作用;
5、检测过时的 context API。

路由配置

Routes , Route , Outlet 路由匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Routes>
<Route path="/" element={<Home></Home>}></Route>
{/* {/* 默认路由,实现路由的重定向 */}
<Route path="/" render={ ()=> <Redirect to="/home"/>}></Route>
<Route path="/home" component={Home}></Route> */}

{/* 默认路由地址不区分大小写的 caseSensitive为true时开启区分大小写 */}
<Route path="about" element={<About />} caseSensitive={true}></Route>

{/* 一级路由 */}
<Route path='/news' element={<News />}>
{/* 二级路由 二级路由及以后的子路由开头都不需要加/ */}
{/* index 默认显示的页面 */}
<Route index element={<div>默认新闻</div>}></Route>
<Route path='china' element={<div>中国新闻</div>}>
{/* 三级路由 */}
</Route>
<Route path='world' element={<div>世界新闻</div>}></Route>
</Route>
<Route path='/useEffect' element={<UseEffect></UseEffect>}></Route>
</Routes>

// <Routes></Routes> 作为路由的容器存在 内包含路由信息
// 注意:子路由需要在页面内 写一个 <Outlet></Outlet> 作为占位容器存在
// end 精准匹配 对跳转的路由
<NavLink to='/news' end>默认</NavLink> // end 精准匹配路由 避免重复高亮
<NavLink to='/news/china'>中国</NavLink>
<NavLink to='/news/world'>世界</NavLink>

路由传参 useParams,useSearchParams,useLocation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
params 传参
{/* :id 设置动态参数 占位符 */}
<Route path='/class/:id' element={<ClassItem></ClassItem>}></Route>

// url : /class/123?hh=666

// 导入hooks useParams,useSearchParams,useLocation
// 获取参数
const {id} = useParams()
console.log(id); // 123

let [query] = useSearchParams()
console.log(query.get('hh')); // 666

let location = useLocation()
console.log(location);
// 路由信息
// {pathname: '/class/123', search: '?hh=666', hash: '', state: null, key: 'sw0esmdd'}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Link, NavLink, useNavigate } from "react-router-dom"

// 声明式导航
<Link to='/class/124'><li>124期</li></Link>
<NavLink to='/class/124'>世界</NavLink> // 自带高亮 “ .active ”

// 编程式导航
let navigate = useNavigate();
// 事件跳转
let ToDetail = (id) => {
console.log(id);
router(`/class/${id}?type=前端&age=5&type=后端`, {state: {a: 1, b: 2}});
}

// 返回上一页
1.window 方法
window.history.back()
2.导入history库(由react-router团队开发,为react-router依赖库)
// 安装
yarn add history
// 使用
import { createHashHistory } from 'history'
const history = createHashHistory({window})
// 事件返回上一页
const backHandle = ()=>{
history.go(-1)
}

路由页面 异步加载,按需加载 进入页面Loading 加载中效果

第一种方法  异步加载   lazy懒惰  懒加载,按需加载  需要搭配Suspense

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 导入加载中效果组件
import Loading from './views/Loading.jsx';

// 将页面组件导入备用
const UseContext = React.lazy(() => import('./views/UseContext.jsx'));

// 使用
<Route path='/useContext' element={
<Suspense fallback={<Loading></Loading>}>
<UseContext></UseContext>
</Suspense>
}>
</Route>

第二种方法  异步加载  可以不使用Suspense  需要安装依赖@loadable/component

1
2
3
4
5
6
7
8
9
10
// 安装
npm install @loadable/component -S

// 导入使用
import loadable from '@loadable/component';
const UseContext = loadable(() => import('./views/UseContext.jsx'), {
fallback: <Loading></Loading>
})

<Route path='/useContext' element={<UseContext></UseContext>}></Route>

配置Redux Toolkit 使用

1. 创建 store 仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 安装  Redux Toolkit
npm install @reduxjs/toolkit react-redux

// 1. 创建 store 仓库 -- 并将第二步构建的模块化仓库导入到主store 仓库中 --

import { configureStore } from '@reduxjs/toolkit'
import productReducer from './product'

export default configureStore({
reducer: {
product: productReducer
}
})


2.模块化仓库 存储数据 定义更新数据方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { createSlice } from '@reduxjs/toolkit'

// 创建分区 类似于vuex中的modules
let product= createSlice({
name: 'product', // 分区的名字
initialState: { // 该区域的初始化的数据
count: 1,
list: ['iphone18 pro max 1TB 暗夜紫']
},
// vuex中如果想要修改仓库里面的数据,mutations里面定义方法区修改,mutaions是唯一一种修改数据的方式
// reducers 相当于是vuex中的mutations
reducers: {
// 第一个参数:初始化的数据, 第二个参数:传递进来的数据
changCount(state, data) {
console.log(state.count, state.list[0], data);
state.count = state.count + data.payload.n;
},
changeList(state, {payload}) {
state.list = payload;
}
}
})

// 默认抛出 引入的时候直接 import xxx from 'xxx'
export default product.reducer;
// 抛出对象 引入的时候需要使用 import {xxx, xxx} from 'xxx'
export let {changCount, changeList} = product.actions; // 将reducers里面的方法抛出


// 在vuex里面有一些异步的操作需要放到actions里面去执行,在aciotns里面去调用mutations里面的方法
// 定义异步方法, 去触发reducers里面的方法
export let getDataSync = playload => dispatch => {
// 模拟请求
setTimeout(() => {
let arr = ['小米13pro', '华为mate70 保时捷版', '三星嘎拉克斯22+'];
dispatch(changeList(arr));
}, 2000);
}

// 同上含义不同写法
export let getDataSync = playload => {
return dispatch => {
// 做些什么操作
}
}

3.导入组件内访问store内数据,并调用方法进行更新操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 使用hook  获取状态管理里面的数据   useDispatch 相当于是vuex中的this.$store.dispatch   this.$store.commit
import { useSelector, useDispatch } from 'react-redux';
import { changCount, getDataSync } from '../store/product'
import { useEffect } from 'react';


export default function() {
// let data = useSelector(state => state); // store里面所有模块的数据
// console.log(data);

// let product = useSelector(state => state.product); // store里面product模块的数据
// console.log(product);

// let {user, product} = useSelector(state => state);
// console.log(user, product);

let {count, list} = useSelector(state => state.product);
console.log(count, list);

let dispatch= useDispatch();

let handleChangeCount = () => {
dispatch(changCount({n: 10}))
}


useEffect(() => {
dispatch(getDataSync());
}, []);


return <div>
<h1>Home页面</h1>
{/* <p>{product.count}--{product.list}</p> */}
<p>{count}--{list}</p>
<button onClick={handleChangeCount}>更改count</button>
</div>
}


请求封装 axios

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 安装 axios
npm i axios

// 1. 使用配置 index.js
import axios from "axios";

export function http(config) {
let instance = axios.create({
baseURL: "https://www.baidu.com", // 请求地址
timeout: 3000, // 请求超时
// retry: 3, //设置全局重试请求次数(最多重试几次请求)
// retryDelay: 1000, //设置全局请求间隔
});

// 添加请求拦截器 在请求之前做些什么

// 添加响应拦截器 在响应之后做些什么

// 拦截器详情参考官网:https://axios-http.com/zh/docs/interceptors

}

// 2. 构建请求 GetData.js
import {http} from './index'

// 首页数据
export function GetHomeData(animal) {
return http({
url: `/xx/xxxx/xxxx/xxxxxxxx`,
})
}

// 3. 页面导入使用 发送请求
import { GetHomeData, GetLikeData } from '../../newwork/getData'

GetHomeData(catOrdog).then(res => {
console.log(res.data); // 对返回数据进行操作
})

useState , useRef , useEffect useContent 总线 插槽

useState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 导入
import { useState } from 'react';

// 使用
let [title,settitle] = useState('哈哈哈')

// 更新数据
settitle('略略略')

// 数组对象更新不能直接赋值
let arr = [1,2,3,4,5,6]
let [arr1,setarr1] = useState(arr)

// 数组对象更新不能直接赋值
let newarr = [4,5,6,7,8]
setarr1(newarr) // 不正确

setarr1([...newarr]) //正确 使用展开运算符

useRef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { useEffect, useRef, useState } from "react"

let myref = useRef('');
console.log(myref.current); // ''

// 页面关联绑定
<h3 ref={myref}>我是h3</h3>

// 获取DOM
// 充当了生命周期的功能
useEffect(() => {
console.log('useEffect,视图渲染结束之后才执行useEffect,相当于vue中的mounted');
// 3、使用
console.log(myref.current); // <h3>我是h3</h3>
}, [])

useEffect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { useEffect, useRef, useState } from "react"

let [count, setCount] = useState(0);
let changeCount = () => {
setCount(10); // setCount方法是一个异步更新数据的方法
console.log(count); // 0
}
useEffect(() => { // 监听器 或者 updated生命周期
console.log(count);
}, [count])

// 还能充当销毁的生命周期 unMounted
useEffect(() => {

return () => { // 组件销毁时执行的回调 unMounted 在组件销毁之前,清除一些只有在当前页面里面才使用的全局事件
console.log('销毁了');
}
}, []) // 如果第二个参数为一个空数组时 仅在第一次渲染时执行一次


useEffect是一个React Hook,用于在组件渲染时执行副作用操作,类似于类组件中的生命周期函数。
useEffect的作用是在组件渲染完成后执行一些操作,比如发送网络请求、订阅事件、更新DOM等。
useEffect接收两个参数,第一个参数是一个函数,用于执行副作用操作,第二个参数是一个数组,用于指定依赖项,当依赖项发生变化时,useEffect会重新执行。
useEffect的执行顺序是在组件渲染完成后执行,如果指定了依赖项,当依赖项发生变化时,useEffect会先执行清除操作,然后再执行副作用操作。

useContent 总线传值 插槽传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1.在src 下创建 mooudle 文件夹 创建bus.js 文件

import React from 'react';
// 实例化一个上下文对象
let myContext = React.createContext();

export default myContext;

2. 在要使用Context 传值的组件中导入使用 <MyContext.Provider></MyContext.Provider> 中包裹要传给的组件
import MyContext from '../modules/bus.js';

import Child1 from '../components/Child1.jsx';
import Child2 from '../components/Child2.jsx';

export default function () {
let person = {
name: 'ikun',
age: 10,
}

return <div>
<h3>演示useContext</h3>

{/* 提供数据 */}
<MyContext.Provider value={person}>
{/* 插槽第一种写法 自定义属性 在child1里面 props.slot接收 */}
<Child1 slot={<img width="100px" src='https://img1.baidu.com/it/u=1960110688,1786190632&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=281' />}></Child1>
<Child1 slot={<img width="100px" src='https://img1.baidu.com/it/u=1472391233,99561733&fm=253&fmt=auto&app=120&f=JPEG?w=889&h=500' />}></Child1>

{/* 插槽第二种写法 内容区传递的 在child2里面 props.children接收 */}
<Child2>
<h1>我是child2的第一个h1</h1>
<h1>我是child2的第二个h1</h1>
<h1>我是child2的第三个h1</h1>
</Child2>
</MyContext.Provider>
</div>
}

3.接收使用 Context 总线上的值

import myContext from "../modules/bus";
import { useContext } from "react";

let value = useContext(myContext);
console.log(value); // { name: 'ikun',age: 10 }

Author: 李金帅

Link: https://lijinshuai21.github.io/Li_JinShuai_Blog/2023/04/01/React%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E5%B0%8F%E8%AE%B0/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

NextPost >
跨域拦截
CATALOG
  1. 1. 创建项目
  2. 2. 路由配置
    1. 2.1. Routes , Route , Outlet 路由匹配
    2. 2.2. 路由传参 useParams,useSearchParams,useLocation
    3. 2.3. 导航路由跳转 Link , NavLink ,
    4. 2.4. 路由页面 异步加载,按需加载 进入页面Loading 加载中效果
      1. 2.4.0.1. 第一种方法  异步加载   lazy懒惰  懒加载,按需加载  需要搭配Suspense
      2. 2.4.0.2. 第二种方法  异步加载  可以不使用Suspense  需要安装依赖@loadable/component
  • 3. 配置Redux Toolkit 使用
    1. 3.1. 1. 创建 store 仓库
    2. 3.2. 2.模块化仓库 存储数据 定义更新数据方法
    3. 3.3. 3.导入组件内访问store内数据,并调用方法进行更新操作
  • 4. 请求封装 axios
  • 5. useState , useRef , useEffect useContent 总线 插槽
    1. 5.1. useState
    2. 5.2. useRef
    3. 5.3. useEffect
    4. 5.4. useContent 总线传值 插槽传递