day3 redux

101 阅读2分钟

Redux

react最常用的集中管理工具,类似于vue中的Pinia(Vuex),可以独立于框架运行。

作用:通过集中管理的方式管理应用状态

  1. 定义一个ruducer函数(根据当前想要做的修改返回一个新的状态)
  2. 使用createStore方法传入ruducer函数 生成一个store=实例对象
  3. 使用store实例的subscribe方法订阅数据的变化(数据一旦变化,可以得到通知)
  4. 使用store实力的dispatch方法提交action对象触发数据变化(告诉reducer你想怎么改数据)
  5. 使用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.actionsconst 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-异步状态操作

  1. 创建store的写法保持不变,配置好同步修改状态的方法

  2. 单独封装一个函数,在函数内部return一个新函数,在新函数中

    1. 封装异步请求获取数据
    2. 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
  3. 组件中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;