reactRouter:
前端路由:一个路径path对应一个组件component当我们在浏览器中访问一个path时,path对应的组件会在页面中进行渲染
抽象路由模块:
路由跳转:
路由系统中的多个路由组件之间需要进行路由跳转,并且在跳转同时需要进行参数传递
通常给组件的to属性指定要跳转的路由path,组件会被渲染为浏览器支持的a链接,如果需要传参直接通过字符串拼接的方式拼接参数即可
Link:
编程式导航:
编程式是指通过'useNavigate'钩子得到的导航方法,然后通过调用方法以命令的方式进行路由跳转
语法说明:通过调用navigate方法传入地址实现跳转
import { useNavigate } from "react-router-dom"
const Login=()=>{
const navigate=useNavigate()
return <div>我是登录页
<button onClick={()=>navigate('/article')}>跳转文章页</button>
<button onClick={()=>navigate('/article/1001')}>searchParams传参</button>
</div>
}
export default Login
导航传参:
获取参数:
useSearchParams返回的是一个数组
params传参:
useParams返回的是一个对象
import { useParams } from "react-router-dom"
const Article=()=>{
const params=useParams()
let id=params.id
return <div>我是文章,{id} </div>
}
export default Article
嵌套路由:
在一级路由中又嵌套了其他路就叫做嵌套路由
实现步骤:
-
使用children属性配置路由嵌套关系
-
使用<Outlet/>组件配置二级路由渲染位置+
import { Link, Outlet } from "react-router-dom"
const Layout=()=>{
return <div>
这是一级路由
<Link to="/">面板</Link>
<Link to="/about">关于</Link>
{/* 配置二级路由的出口*/}
<Outlet/>
</div>
}
export default Layout
当访问的是一级路由时,默认的二级路由组件可以得到渲染,只需要在二级路由的位置去掉path,设置index属性为true
路由模式:
react提供两种路由模式:history模式和Hash模式,reactRouter分别由createBrowerRouter和createHashRouter函数创建
路由模式 | url表现 | 底层原理 | 是否需要后端只支持 |
---|---|---|---|
history | url/login | history对象+pushState对象 | 需要 |
hash | url/#/login | 监听hashChange事件 | 不需要 |
redux:
redux是react最常用的集中状态管理工具,可以独立于框架运行
react本质上是一个UI库,他是单项数据流的,数据只能从父组件通过props传给子组件,如果子组件想要修改父组件的值,只能通过绑定函数传递参数的形式来修改,数据比较复杂时,不好操作,所以需要redux协助
作用:通过集中管理的方式管理应用的状态
redux把整个数据的修改分成了三个核心概念,分别是:state、action、reducer
-
state:一个对象 存放着我们管理的数据状态
-
action:一个对象 用来描述你想怎样改数据
-
reducer: 一个函数 根据action的描述生成一个新的state
在react组件中使用store中的数据,需要拥有一个钩子函数-useSelector,它的作用是把store中的数据映射到组件中
React组件中修改store中的数据需要借助另一个hook函数-useDispatch,它的作用是生成提交action对象的dispatch函数
action传参:
在reducers的同步修改方法中添加action对象参数,再调用actionCreater的时候传递参数,参数会被传递到action对象payload属性上
redux遵循的三个原则:
-
单一真实数据源。
-
状态是只读的
-
使用纯函数来进行修改
创建store
import { createSlice } from '@reduxjs/toolkit'
import axios from 'axios'
const dataStore=createSlice({
name:'data',
initialState:{
dataMoney:[]
},
reducers:{
setBillData(state,actions){
state.dataMoney=actions.payload
}
})
const {setBillData,addBill}=dataStore.actions
let reducer=dataStore.reducer
redux异步操作:
-
创建store的写法保持不变,配置好同步修改状态的方法
-
单独封装一个函数,在函数内部return一个新函数,在新函数中
3.组件中的dispatch写法保持不变
-
封装异步请求获取数据
-
调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
-
const fetchData=()=>{
return async (dispatch)=>{
const res=await axios.get('http://localhost:8888/ka')
dispatch(setBillData(res.data))
}
}
获取数据:
const dataMoney=useSelector(state=>state.money.dataMoney)//获取数据
useEffect(()=>{
dispatch(fetchData())
},[dispatch])
useMemo():
useMemo是react的一个重要的性能优化工具,可以避免在渲染过程中的不必要计算,从而提高组件性能
第一个参数是一个函数,用于进行计算,第二个参数是一个依赖数组,当依赖发生变化时会重新进行计算,useMemo会在每次渲染都计算新的值
import { useMemo } from "react";
import { useState } from "react";
// 消耗非常大的计算才用useMemo
function fib(n){
console.log("函数执行了");
if(n<3)
return 1
return fib(n-2)+fib(n-1)
}
function App() {
const [count1,setCount1]=useState(0)
const result= useMemo(()=>{
console.log('组建重新渲染');
return fib(count1)
},[count1])
const [count2,setCount2]=useState(0)
return (
<div className="App">
this is App
<button onClick={()=>setCount1(count1+1)}>change count1:{count1}</button>
<button onClick={()=>setCount2(count2+1)}>change count2:{count2}</button>
{result}
</div>
);
}
export default App;
useReducer:
和useState的作用类似,用来管理相对复杂的状态数据
import { useReducer } from "react"
//定义reduce函数,根据不同的action返回不同的状态
function reducer(state,action){
switch(action.type){
case 'INC':
return state+1
case 'DEC':
return state-1
case 'SET':
return action.payload
default:
return state
}
}
//在组件中调用useReducer(reducer,0)=>[state,dispatch]
//调用dispatch({type:'INC})
function App() {
const [state,dispatch]=useReducer(reducer,0)
return(
<div className="App">
this is App
<button onClick={()=>dispatch({type:'INC'})}>+</button>
{state}
<button onClick={()=>dispatch({type:'DEC'})}>-</button>
<button onClick={()=>dispatch({type:'SET',payload:100})}>update</button>
</div>
)
}
export default App;
参数:
reducer:用于更新state的纯函数、。参数为state和action,返回值是更新后state
initialArg:用于初始state的任意值。初始值的计算逻辑取决于接下来的init参数
可选参数:用于计算函数的初始值,如果存在使用init(initialArg)的执行结果作为初始值。否则使用initialArg
返回值:返回一个有两个之组成的数组
dispatch返回的dispatch函数允许你更新state并触发组件的重新渲染
react.memo:
作用:允许组件在Props没有改变的情况下跳过渲染
React组件默认渲染机制:只要父组件重新渲染子组件就会重新渲染
经过memo函数包裹生成的缓存组件只有在props发生变化时才会重新渲染
import { useMemo } from "react";
import { useState } from "react";
import { memo } from "react";
//传递一个简单类型的porp
//传递一个引用类型 当父组件的函数重新执行时,实际上形成的是新的数组引用
const MemoComponent=memo(function Son(){
console.log('我是子组件,我要重新渲染' );
return <div>this is son </div>
})
function App() {
const list=useMemo(()=>{
return [1,2,3]
},[])
const [count,setCount]=useState(0)
return (
<div className="App">
this is App
<MemoComponent list={list} />
<button onClick={()=>setCount(count+1)}>+</button>
{count}
</div>
);
}
export default App;
react.memo-props的比较机制
机制:在使用memo缓存组件后,React会对每一个prop使用Object.js比较新值和老值,返回true,表示没有变化
prop是简单类型
Object.is(3,3)没有变化
prop是引用类型(对象/数组)
Object([],[])=>false 有变化,react只关心引用是否变化
当时用引用类型时:利用useMemo()组件渲染缓存的过程中缓存一个值