一、Redux
集中状态管理工具,不需要react即可使用,每个store的数据都是独立于组件之外的
vue小链接:vuex/pinia
基本使用
Redux将数据修改流程分成三个概念,state、action和reducer
state - 一个对象 存放我们管理的数据状态
action - 一个对象 描述你如何修改数据
reducer - 一个函数 根据action的描述生成新的state
javascript
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
<script>
// 1. 定义reducer函数
// 作用: 根据不同的action对象,返回不同的新的state
// state: 管理的数据初始状态
// action: 对象 type 标记当前想要做什么样的修改
function reducer (state = { count: 0 }, action) {
// 数据不可变:基于原始状态生成一个新的状态 所以要返回新对象
if (action.type === 'INCREMENT') {
return { count: state.count + 1 }
}
if (action.type === 'DECREMENT') {
return { count: state.count - 1 }
}
return state
}
// 2. 使用reducer函数生成store实例
const store = Redux.createStore(reducer)
// 3. 通过store实例的subscribe订阅数据变化
// 回调函数可以在每次state发生变化的时候自动执行
store.subscribe(() => {
console.log('state变化了', store.getState())
document.getElementById('count').innerText = store.getState().count
})
// 4. 通过store实例的dispatch函数提交action更改状态
const inBtn = document.getElementById('increment')
inBtn.addEventListener('click', () => {
// 增
store.dispatch({
type: 'INCREMENT'
})
})
const dBtn = document.getElementById('decrement')
dBtn.addEventListener('click', () => {
// 减
store.dispatch({
type: 'DECREMENT'
})
})
// 5. 通过store实例的getState方法获取最新状态更新到视图中
</script>
react中使用redux
相关工具
Redux Toolkit 简化redux书写逻辑
react-redux 链接Redux和React的中间件
javascript
npm i @reduxjs/toolkit react-redux
安装成功
目录创建
创建src/store,modules存放子模块
counterStore.js
javascript
//1 导入并创建store
import {createSlice} from "@reduxjs/toolkit"
const counterStore = createSlice({
name:'counter',
// 初始状态
initialState:{
count:0
},
// 更新状态的方法
reducers:{
inscrement(state){
state.count++
},
descrement(state){
state.count --
}
}
})
const {inscrement, descrement} = counterStore.actions
const reducer = counterStore.reducer
export{
inscrement,
descrement
}
export default reducer
store/index.js
集成store/modules中所有子模块
javascript
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./modules/counterStore"
// 将子模块中的所有store合成一个根store方便访问
const store = configureStore({
reducer:{
counter:counterReducer,
}
})
export default store
src/index.js
javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./store"
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// 通过react-redux提供的Provider 给组件注入store 使得redux定义的store能够被react组件使用
<Provider store={store}>
<App />
</Provider>
);
App.js
useDispatch() 通过这个来派发reducer修改状态
javascript
import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement} from "./store/modules/counterStore"
function App() {
const { count } = useSelector(state => state.counter)
const dispatch = useDispatch()
return (
<div className="App">
<button onClick={() => dispatch(inscrement())}>+</button>
{count}
<button onClick={() => dispatch(descrement())}>-</button>
</div>
);
}
export default App;
然后就完成了:
进阶版-提交action时传参
counterStore.js
增加了一个addToNum函数
javascript
//1 导入并创建store
import {createSlice} from "@reduxjs/toolkit"
const counterStore = createSlice({
name:'counter',
// 初始状态
initialState:{
count:0
},
// 更新状态的方法
reducers:{
inscrement(state){
state.count++
},
descrement(state){
state.count --
},
addToNum(state, action){
// dispatch调用该方法时传入的参数就存放在action.payload
state.count += action.payload
}
}
})
const {inscrement, descrement, addToNum} = counterStore.actions
const reducer = counterStore.reducer
export{
inscrement,
descrement,
addToNum
}
export default reducer
App.js
增加了两个值,传入不同参数
javascript
import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement, addToNum} from "./store/modules/counterStore"
function App() {
const { count } = useSelector(state => state.counter)
const dispatch = useDispatch()
return (
<div className="App">
<button onClick={() => dispatch(inscrement())}>+</button>
{count}
<button onClick={() => dispatch(descrement())}>-</button>
<button onClick={() => dispatch(addToNum(10))}>+ 10</button>
<button onClick={() => dispatch(addToNum(-10))}>- 10</button>
</div>
);
}
export default App;
再进阶版-异步状态操作
channelStore.js
javascript
import {createSlice} from '@reduxjs/toolkit'
import axios from 'axios'
const channelStore = createSlice({
name:'channel',
initialState:{
channelList:[]
},
reducers:{
getChannels(state, action){
state.channelList = action.payload
}
}
})
const {getChannels} = channelStore.actions
//单独写一个异步action的函数 异步操作处理完毕后再调用同步action修改状态
const getChannelList = () => {
return async(dispatch) => {
const res = await axios.get('http://geek.itheima.net/v1_0/channels')
dispatch(getChannels(res.data.data.channels))
}
}
export {getChannelList}
const reducer = channelStore.reducer
export default reducer
App.js
javascript
import { useSelector, useDispatch } from "react-redux";
import {inscrement, descrement, addToNum} from "./store/modules/counterStore"
import {getChannelList} from "./store/modules/channelStore"
import {useEffect} from 'react'
function App() {
const { count } = useSelector(state => state.counter)
const { channelList } = useSelector(state => state.channel)
const dispatch = useDispatch()
useEffect(()=> {
dispatch(getChannelList())
}, [dispatch])
return (
<div className="App">
<button onClick={() => dispatch(inscrement())}>+</button>
{count}
<button onClick={() => dispatch(descrement())}>-</button>
<button onClick={() => dispatch(addToNum(10))}>+ 10</button>
<button onClick={() => dispatch(addToNum(-10))}>- 10</button>
<ul>
{channelList.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
</div>
);
}
export default App;
调试工具redux devtools
直接在chorme商店里下载