redux
这篇文章谈一谈仓库redux。
首先,学习任何东西都离不开官网。在此附上官网网址
Redux - A predictable state container for JavaScript apps. | Redux
1.什么是redux?
从如下几个方面:
redux在一个项目中可集中管理状态(数据)和逻辑代码,让你开发出强大的功能。
redux一般在中大型项目较为适用,小型项目建议使用订阅发布。
主要用于处理各个组件之间的通信问题。
2.使用redux的三大原则–规范
1.整个应用的数据state,只存放在唯一的store中。
2.state是只读的,唯一改变state数据的方法,是通过action自定义事件去修改。action是一个对象。通过Store.dispatch()去调用。
3.action自定义事件是需要通过纯函数的方式去触发的,因此需要编写与useReducer结构类似的函数去修改。reduce函数有两个参数:
参数一:上一次state的数据
参数二:传递过来的action
reduce函数要返回新的state数据。
3.原理过程分析:
初始化阶段:
仓库store-视图view(组件)
1.首先使用最顶层的reducer函数,创建redux-store。
createStore(callback)接受一个回调函数。这个回调函数就是最顶层的reducer函数
2.store调用一次reducer函数,并将返回值作为最新的state数据
3.与view框架交互,并将state数据渲染到UI视图层上面去,同时监听store的存在,以便知道state的更新
更新阶段
1.用户通过行为触发事件
2.通过store.dispatch()一个action给reducer进行state数据的处理。
3.此时数据虽然更改了,但有一个问题,没有触发视图的更新。有两种解决方案,一种是使用useState中的函数,还有一种就是重新渲染app组件。可能大家会认为非常损耗性能,但diff算法帮我们节省了性能
4.store 通知所有订阅过的 UI,通知它们 store 发生更新每个订阅过 store 数据的 UI 组件都会检查它们需要的 state 部分是否被更新。发现数据被更新的每个组件都强制使用新数据重新渲染,紧接着更新网页
4.使用
安装redux
npm i redux
然后就可以使用了
计数器小demo:
建立redux文件夹
store.js
import { createStore } from 'redux'
import { aa } from './reducers'
export default createStore(aa)
reducers.js
function aa(state = { num: 1 }, actions) {
console.log(state, actions);
let num = state.num
switch (actions.type) {
case "add":
num = num + actions.data
return { num }
default:
break;
}
return state
}
export {
aa
}
index.js进行数据监听
// 操作dom
import ReactDOM from "react-dom/client";
// 引入App组件
import App from "./App"
// 引入css文件
import "./app.scss"
import store from "./redux/store"
import { BrowserRouter } from "react-router-dom"
// 设置挂载位置
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
<App />
)
store.subscribe(() => {
root.render(
<App />
)
})
5.一个基础完整的redux实例代码
App.js
import React from 'react'
import store from "./redux/store"
import { createAdd, createDel } from './redux/action/createSum'
export default function App() {
let { num } = store.getState()
const handleAdd = () => {
store.dispatch(createAdd())
}
const handleDel = () => {
store.dispatch(createDel())
}
return (
<div>
<p>数据之{num}</p>
<button onClick={handleAdd}>Add1</button>
<button onClick={handleDel}>Del1</button>
</div>
)
}
redux/action/createSum.js
export const createAdd = () => {
return { type: 'add', data: 1 }
}
export const createDel = () => {
return { type: 'del', data: 1 }
}
redux/store.js
import { createStore } from 'redux'
import { aa } from './reducer/reducers'
export default createStore(aa)
redux/reducer/reducers.js
let init = { num: 1 }
function aa(state = init, actions) {
console.log(state, actions);
//由于纯函数的规范,返回是新的值
let newState = { ...state }
switch (actions.type) {
case "add":
newState.num = newState.num + actions.data
return newState
case "del":
newState.num -= actions.data
default:
break;
}
return newState
}
export {
aa
}
6.redux store里面处理异步
需要引入插件 redux-thunk
在store.js中引入
import { createStore, applyMiddleware } from 'redux'
import { aa } from './reducer/reducers'
import reduxThunk from 'redux-thunk'
export default createStore(aa, applyMiddleware(reduxThunk))
7.react-redux
小分类?
react-redux 旧版本 函数与class都通用
react-toolkit hooks版本,函数用的
什么是react-redux?
redux是一个独立的仓库,可以和市面上流行的框架例如Vue,angular,react等ui框架结合一起使用。如果我们要同时使用react和redux的时候,我们建议不要直接把react组件内容和store进行交互,而是应该将react-redux作为中间桥梁连接其中。
- 容器组件 包裹 UI组件 通过容器组件 与 redux进行操作
- 容器组件操作仓库 仓库数据给容器组件, 容器组件将数据给UI组件
- UI组件触发 容器组件发送action 给仓库进行修改数据
使用:
安装
npm i react-redux
初始版本:
components/SumUI
import React from 'react'
import store from "../redux/store"
import { createAdd, createDel, createAsync } from '../redux/action/createSum'
export default function SumUI(props) {
console.log(props);
let num = props.num
const handleAdd = () => {
props.handleAdd()
}
const handleDel = () => {
props.handleDel()
}
const handleAsync = () => {
props.handleAsync()
}
return (
<div>
<p>数据之{num}</p>
<button onClick={handleAdd}>Add1</button>
<button onClick={handleDel}>Del1</button>
<button onClick={handleAsync}>异步加</button>
</div>
)
}
containner/Sum
import { connect } from 'react-redux'
import SumUI from '../component/SumUI'
import { createAdd, createDel, createAsync } from '../redux/action/createSum'
function mapStateToProps(state) {
return state
}
const mapDispatchToProps = (dispatch) => {
return {
handleAdd: () => dispatch(createAdd()),
handleDel: () => dispatch(createDel()),
handleAsync: () => dispatch(createAsync())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SumUI)
App.js
import React from 'react'
import Sum from './container/Sum'
import store from './redux/store'
export default function App() {
return (
<div>
<Sum store={store}></Sum>
</div>
)
}
优化点:
1.mapStateToProps直接在connect里面写回调函数
2.mapDispatchToProps可以写成对象形式。系统会自动用dispatch包裹。
Sum.jsx优化
import { connect } from 'react-redux'
import SumUI from '../component/SumUI'
import { createAdd, createDel, createAsync } from '../redux/action/createSum'
export default connect(state => state, {
handleAdd: createAdd,
handleDel: createDel,
handleAsync: createAsync
})(SumUI)
8.多组件之间通信
关键api:combineReducer
9.使用redux-devtools
如果要使用redux-devtools,我们需要使用第三方插件
安装 redux-devtools-extension,然后在store.js中配置
import {applyMiddleware, createStore,combineReducers} from "redux"
// 引入stroe异步中间件
import Thunk from "redux-thunk"
// 引入所有的纯函数reduce
import reduce from "./index"
// 使用插件查看数据
import {composeWithDevTools} from "redux-devtools-extension"
// 暴露仓库(store)
export default createStore(reduce,composeWithDevTools(applyMiddleware(Thunk)))
10.react-redux提供自定义的hooks
需要三个 redux react-redux @reduxjs/toolkit
1.创建store redux/store.js
// 开始准备创建仓库
import { configureStore } from '@reduxjs/toolkit';
// 引入纯函数
import reducerSum from "./reducers/reduceSum"
// 返回值就是仓库
const store = configureStore({
// 每个组件的纯函数
reducer:{
reducerSum
}
})
export default store
2.创建reducer纯函数 reducers/reduceSum.js
// 通过@reduxjs/toolkit创建纯函数
import {createSlice} from "@reduxjs/toolkit"
// 创建纯函数
const reducerSum = createSlice({
name:"reducerSum", // 名称
initialState:{ // 初始数据 对象
num:0,
qwe:"大哥"
},
reducers:{ // 重新处理数据
ADD:(state,action)=>{ // 数据加
console.log(action);
// state 代表数据原
state.num = state.num + action.payload
},
Reduce:(state,action)=>{
state.num = state.num - action.payload
},
}
})
console.log(reducerSum,123);
export const {ADD,Reduce} = reducerSum.actions; // 暴露行为给组件调用
export default reducerSum.reducer; // 暴露reduce纯函数给仓库store
组件使用数据
import { useStore, useSelector, useDispatch } from "react-redux"
import { Reduce } from "../redux/reducers/reduceSum"
export default function Sum() {
const store = useStore()
console.log(store.getState().reducerSum.num,"useStore");
const {num,qwe} = useSelector((state)=>state.reducerSum)
console.log(num,"num");
const dispatch = useDispatch()
const handlAdd = ()=>{
// dispatch({type: 'reducerSum/ADD',payload:1})
// ADD(123)
// dispatch(ADD(123))
}
const handlreduc = ()=>{
dispatch(Reduce(10))
}
return (
<div>
<p>Sum--{store.getState().reducerSum.num}</p>
<p>{num}--{qwe}</p>
<button onClick={handlAdd}>点击夹</button>
<button onClick={handlreduc}>点击减</button>
</div>
)
}
书写redux的规范
1.纯函数不要返回修改上一次的state数据,建议复制一下数据,然后进行修改,再进行返回数据
/ dispatch({type: ‘reducerSum/ADD’,payload:1})
// ADD(123)
// dispatch(ADD(123))
}
const handlreduc = ()=>{
dispatch(Reduce(10))
}
return (
Sum–{store.getState().reducerSum.num}
{num}–{qwe}
点击夹
点击减
</div>
)
}
## 书写redux的规范
> 1.纯函数不要返回修改上一次的state数据,建议复制一下数据,然后进行修改,再进行返回数据
>
> 2.reducer不要执行任何异步操作,仅仅修改数据,赋值就好了。负责修改state数据