Redux
react最常用的集中管理工具,类似于vue中的Pinia(Vuex),可以独立于框架运行。
作用:通过集中管理的方式管理应用状态
- 定义一个ruducer函数(根据当前想要做的修改返回一个新的状态)
- 使用createStore方法传入ruducer函数 生成一个store=实例对象
- 使用store实例的subscribe方法订阅数据的变化(数据一旦变化,可以得到通知)
- 使用store实力的dispatch方法提交action对象触发数据变化(告诉reducer你想怎么改数据)
- 使用store实例的getState方法获取最新的状态数据更新到视图中
<button id="increment">+</button>
<span id="count">0</span>
<button id="decrement">-</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())
//使用store实例的getState方法获取最新的状态数据更新到视图中
document.getElementById('count').innerText = store.getState().count
})
//4.通过实例的dispatch函数提交action更改状态
const inBtn = document.getElementById('increment')
inBtn.addEventListener('click',()=>{
store.dispatch({
type:"INCREMENT"
})
})
const deBtn = document.getElementById('decrement')
deBtn.addEventListener('click',()=>{
store.dispatch({
type:"DECREMENT"
})
})
</script>
使用React Toolkit 创建 counterStore
// src/store/modules/counterStore.js
import {createSlice} from "@reduxjs/toolkit";
const counterStore = createSlice({
name:'count',
//初始化state
initialState:{
count:0
},
//修改状态的方法 同步方法 支持直接修改
reducers:{
increment(state){
state.count++;
},
decrement(state){
state.count--;
}
}
})
//结构出来actionStore函数
const {increment,decrement} = counterStore.actions
const reducer = counterStore.reducer;
//以按需的导出方式导出actionCreater
export {increment,decrement}
//默认方式导出reducer
export default reducer;
// src/store/index.js
import {configureStore} from "@reduxjs/toolkit";
import counterReducer from "./modules/counterStore"
const store = configureStore({
reducer:{
counter:counterReducer
}
})
export default store;
// src/App.js
import {useDispatch, useSelector} from "react-redux";
import {decrement, increment} from "./store/modules/counterStore";
function App() {
const { count } = useSelector(state => state.counter)
const dispatch = useDispatch()
return (
<div>
<button onClick={()=>dispatch(decrement())}> -</button>
{count}
<button onClick={()=>dispatch(increment())}> +</button>
</div>
);
}
export default App;
感觉redux用起来真的很麻烦且不易懂,比vue的pinia麻烦很多。
提交action传参
addToNumber(state, action) {
state.count = action.payload
}
const {increment, decrement,addToNumber} = counterStore.actions
export {increment, decrement,addToNumber}
<button onClick={()=>dispatch(addToNumber(10))}>add To Ten</button>
<button onClick={()=>dispatch(addToNumber(20))}>add To Twenty</button>
Redux与React-异步状态操作
-
创建store的写法保持不变,配置好同步修改状态的方法
-
单独封装一个函数,在函数内部return一个新函数,在新函数中
- 封装异步请求获取数据
- 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
-
组件中dispatch的写法保持不变
// src/sotre/modules/channelStore
import {createSlice} from "@reduxjs/toolkit";
import axios from "axios";
const channelStore = createSlice({
name:'channel',
initialState:{
channelList:[]
},
reducers:{
setChannels(state,action){
state.channelList = action.payload
}
}
})
const {setChannels} = channelStore.actions;
const fetchChannelList = ()=>{
return async (dispatch)=>{
const res =await axios.get('http://geek.itheima.net/v1_0/channels')
dispatch(setChannels(res.data.data.channels))
}
}
export {fetchChannelList}
const reducer = channelStore.reducer
export default reducer
// src/store/index.js
import {configureStore} from "@reduxjs/toolkit";
import channelReducer from "./modules/channelStore"
const store = configureStore({
reducer:{
channel:channelReducer
}
})
export default store;
// App.js
import {useDispatch, useSelector} from "react-redux";
import {useEffect} from "react";
import {fetchChannelList} from "./store/modules/channelStore";
function App() {
const {channelList} = useSelector(state => state.channel)
const dispatch = useDispatch()
useEffect(() => {
dispatch(fetchChannelList())
}, [dispatch]);
return (
<div>
<ul>
{channelList.map(item=> <li key={item.id}>{item.name}</li>)}
</ul>
</div>
);
}
export default App;