【React】 redux-toolkit 和 react-redux

0. 概述

基础特点

  • 单向数据流,view 发出 action,store 调用 reducer 计算出新的 state,若 state 产生变化,则调用监听函数重新渲染 view

  • 单一数据源,只有一个 Store

  • state 是只读的,每次状态更新之后只能返回一个新的 state

  • 没有 dispatcher,而是在 store 中集成了 dispatch 方法,store.dispatch() 是view 发出 action 的唯一途径

  • 支持使用中间件(Middleware)管理异步数据流

在这里插入图片描述

redux 的发展

redux 是一个独立的第三方库,之后 react 官方在 redux 的基础上推出了 react-redux,全面拥抱 hooks。

此外,redux 官方也推出了 redux toolkit,简化使用 redux 的过程,因为一般在 react 应用中,我们使用 react-redux + redux toolkit 。

1. Redux 快速上手

Redux 是 React 最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行。

npm i redux
<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) {
    switch (action.type) {
      case 'INCREMENT':
        // state 是对象,所以返回的数据也是对象
        return { count: state.count + 1 }
      case 'DECREMENT':
        return { count: state.count - 1 }
      default:
        return state
    }
  }
  // 2. 使用reducer函数生成store实例
  const store = Redux.createStore(reducer)

  // 3. 通过 store 实例的 subscribe 订阅数据变化
  // 回调函数在每一次 state 发生变化时自动执行
  store.subscribe(() => {
    console.log(store.getState())
    document.getElementById('count').innerText = store.getState().count

  })
  // 4. 通过 store 的 dispatch 函数提交 action 的更改状态
  const inBtn = document.getElementById('increment')
  inBtn.addEventListener('click', () => {
    // 匹配的是 action 对象,所以传入 action 对象
    store.dispatch({
      type: 'INCREMENT'
    })
  })
  // 减
  const dBtn = document.getElementById('decrement')
  dBtn.addEventListener('click', () => {
    store.dispatch({
      type: 'DECREMENT'
    })
  })
</script>

2.png

2. React 中使用 Redux

2.1 配制环境

  1. Redux Toolkit(RTK)- 官方推荐编写Redux逻辑的方式,简化书写方式
  2. react-redux - 用来链接 Redux 和 React组件的中间件
npx create-react-app react-redux-demo
npm i @reduxjs/toolkit  react-redux 

2.2 使用 RTK + react-redux

创建 counterStore

// @/store/modules/counterStore.js
import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  // 模块名称唯一
  name: 'counter',
  // 初始 state
  initialState: {
    count: 1
  },
  // 修改数据的同步方法 支持直接修改
  reducers: {
    increment (state) {
      state.count++
    },
    decrement(state){
      state.count--
    },
    addToNum(state, action) {
      state.count = action.payload
    }
  }
})
// 解构出 actionCreater 函数
const { increment,decrement, addToNum } = counterStore.actions

// 获取 reducer 函数
const counterReducer = counterStore.reducer

// 导出
export { increment, decrement, addToNum }
export default counterReducer
// @/store/modules/channelStore.js
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 fetchChannlList = () => {
  return async (dispatch) => {
    const res = await axios.get('http://geek.itheima.net/v1_0/channels')
    dispatch(setChannels(res.data.data.channels))
  }
}

export { fetchChannlList }

const reducer = channelStore.reducer

export default reducer

另一种处理异步请求的方式:

import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
import {getType} from "../../api/type";

export const getTypeList = createAsyncThunk(
    'type/getTypeList',
    async () => {
        const response = await getType()
        return response.data.data
    }
)

const typeStore = createSlice({
    name: 'type',
    initialState: {
        // 存储所有的类型
        typeList: []
    },
    reducers: {},
    // 处理异步的 reducer
    extraReducers: (builder) => {
        builder.addCase(getTypeList.fulfilled, (state, action) => {
            state.typeList = action.payload
        })
    }
})
export default typeStore.reducer
// @/store/index.js
import { configureStore } from '@reduxjs/toolkit'

import counterReducer from './modules/counterStore'

export default configureStore({
  reducer: {
    // 注册子模块
    counter: counterReducer
  }
})

为 React 注入 store

// @/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 导入store
import store from './store'
// 导入store提供组件Provider
import { Provider } from 'react-redux'

ReactDOM.createRoot(document.getElementById('root')).render(
  // 提供store数据
  <Provider store={store}>
    <App />
  </Provider>
)

在 React 组件中使用修改 store 中的数据

// App.js
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
// 导入actionCreater
import { inscrement, decrement, addToNum } from './store/modules/counterStore'
import { fetchChannlList } from './store/modules/channelStore'

function App () {
  // useSelector 函数将 store 中的数据映射到组件中 counter 是 store 名字
  const { count } = useSelector(state => state.counter)
  const { channelList } = useSelector(state => state.channel)
  const dispatch = useDispatch()
  // 使用useEffect触发异步请求执行
  useEffect(() => {
    dispatch(fetchChannlList())
  }, [dispatch])
  return (
    <div className="App">
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(inscrement())}>+</button>
      {/* 变为10 和 变为20 */}
      <button onClick={() => dispatch(addToNum(10))}>add To 10</button>
      <button onClick={() => dispatch(addToNum(20))}>add To 20</button>
      <ul>
        {channelList.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  )
}

export default App

2.3 总结

  • createSlice

A function that accepts an initial state, an object full of reducer functions, and a “slice name”, and automatically generates action creators and action types that correspond to the reducers and state.
这个函数接受一个初始 state、一个充满 reducer 函数的对象和一个“片名”,并自动生成与 reducer 和 state 对应的 action creators 和 action types 。

  • configureStore

A friendly abstraction over the standard Redux createStore() function.
Params:
options – The store configuration.
Returns:
A configured Redux store.
对标准Redux createStore()函数的友好抽象。参数:options—存储配置。返回:已配置的Redux存储。

const channelStore = createSlice({
    name: 'channel',
    initialState: {
        channelList: []
    },
    reducers: {
        setChannels(state, action) {
            state.channelList = action.payload
        },
    }
})
// 解构出来 actionCreator 函数(修改状态数据的函数)
const {setChannels} = channelStore.actions
// 获取 reducer
const reducer = channelStore.reducer
// 以按需导出的方式导出 actionCreator 生成 action 对象 的函数
export {setChannels}
// 导出 reducer 函数
export default reducer
const store = configureStore({
	// 接收 子 reducer 并导入合并
    reducer: {
        counter: counterReducer,
        channel: channelReducer
    }
})

export default store
function App() {
	// 获取 reducer 并解构出 state
    const {count} = useSelector(state => state.counter)
    // 生成提交 action 对象的 dispatch 函数,用于辅助修改 state
    const dispatch = useDispatch()
    const {channelList} = useSelector(state => state.channel)
    // useEffect 触发异步请求执行
    useEffect(() => {
        dispatch(fetchChannelList())
    }, [dispatch]);
    return (
        <div>
            {/*dispatch 触发 actionCreater 修改数据*/}
            <button onClick={() => dispatch(decrement())}> -</button>
            {count}
            <button onClick={() => dispatch(increment())}> +</button>
            <button onClick={() => dispatch(addToNum(10))}> + 10</button>
            <ul>
                {channelList.map(item => (
                    <li key={item.id}>{item.name}</li>
                ))}
            </ul>
        </div>
    );
}
  • initialState 初始化 state(数据状态)
  • reducers 修改状态数据的函数

接收两个参数 state 和 action。而 action.payload 是传入的参数。

组合 redux 和 react:

    <Provider store={store}>
        <App />
    </Provider>

异步操作

  1. 配置同步修改状态的方法
  2. 单独封装一个函数,在函数内部return一个新函数,在新函数中
    2.1 封装异步请求获取数据
    2.2调用同步actionCreator传入异步数据生成一个action对象,并使用dispatch提交

异步获取数据,同步修改数据

const fetchChannelList = () => {
	// 这里可以直接使用 dispatch
    return async (dispatch)=> {
        const res = await axios.get('http://geek.itheima.net/v1_0/channels')
        dispatch(setChannels(res.data.data.channels))
    }
}
export {fetchChannelList}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
要安装redux-toolkit,你可以按照以下步骤进行操作: 1. 在你的项目中打开终端或命令行界面。 2. 运行以下命令来安装redux-toolkit: ``` npm install @reduxjs/toolkit ``` 或者如果你使用的是yarn,可以运行以下命令: ``` yarn add @reduxjs/toolkit ``` 3. 安装完成后,你可以在你的代码中引入redux-toolkit的configureStore函数,例如: ```javascript import { configureStore } from '@reduxjs/toolkit'; ``` 4. 接下来,你可以使用configureStore函数来创建和配置你的Redux store。你可以在reducer参数中传入你的reducer函数,或者使用combineReducers函数来合并多个reducer。例如: ```javascript import { configureStore, combineReducers } from '@reduxjs/toolkit'; // 导入你的reducer函数 import counterReducer from './reducers/counterReducer'; import todosReducer from './reducers/todosReducer'; // 合并多个reducer const rootReducer = combineReducers({ counter: counterReducer, todos: todosReducer, }); // 创建Redux store const store = configureStore({ reducer: rootReducer, }); ``` 5. 现在你已经成功安装了redux-toolkit并创建了Redux store,你可以在你的React组件中使用Provider组件来将store传递给你的应用程序。例如: ```javascript import React from 'react'; import { Provider } from 'react-redux'; import store from './store'; import App from './App'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); ``` 这样,你就可以在你的React组件中使用Redux store了。 #### 引用[.reference_title] - *1* *3* [redux toolkit 傻瓜教学](https://blog.csdn.net/wangyangnuli/article/details/122520675)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Redux流程分析 传统流程和redux-toolkit的使用](https://blog.csdn.net/qq_23539691/article/details/119720636)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值