• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

redux的@reduxjs/toolkit + Hooks用法

武飞扬头像
仟北代~
帮助1

新特性的出现都是解决了旧用法的一些不足之处 !

1. 下载 @reduxjs/toolkit    npm install @reduxjs/toolkit

再下载 react-redux        npm install react-redux  // 这里还要用到react-redux, 是因为连接组件和数据的时候, 仍然使用的是react-redux, @reduxjs/toolkit 只是替代了redux的方案

学新通

 2. 在index.js中引入使用

  1.  
    import React from "react";
  2.  
    import ReactDOM from "react-dom/client";
  3.  
    import App from "./App";
  4.  
    import store from './hookRedux/index' // hook组件的redux
  5.  
    import { Provider } from "react-redux";
  6.  
     
  7.  
    const root = ReactDOM.createRoot(document.getElementById("root"));
  8.  
    root.render(
  9.  
    <Provider store={store}>
  10.  
    <React.StrictMode>
  11.  
    <App />
  12.  
    </React.StrictMode>
  13.  
    </Provider>
  14.  
    );

我的目录结构如下

hookPage里面都是容器组件(所谓容器组件就是, 使用react-redux连接了数据和页面的组件)

hookRedux里面都是store相关的数据, 包括全局属性, 全局状态, 全局事件等

学新通

 在App.js中引入组件

  1.  
    // App.js 的代码
  2.  
    import React from 'react'
  3.  
    import Name from './hookPage/name'
  4.  
    import Counter from './hookPage/counter'
  5.  
    function App() {
  6.  
    return (
  7.  
    <div>
  8.  
    <Name />
  9.  
    <Counter />
  10.  
    </div>
  11.  
    )
  12.  
    }
  13.  
    export default App

3. 从 @reduxjs/toolkit开始实现全局状态

在@reduxjs/toolkit(下面简称rt)中, 导出了一个 配置函数,configureStore , 该函数返回的结果指向了一个合并了所有reducer的容器, 在这里可以做一个统一的出口, 代码如下

  1.  
    // hookReducer 的index.js的文件
  2.  
    import { configureStore } from "@reduxjs/toolkit";
  3.  
    // counterReducer状态管理store , 下一步会写到
  4.  
    import counterReducer from "./modules/counter";
  5.  
    // nameReducer状态管理的store
  6.  
    import nameReducer from './modules/name'
  7.  
    const store = configureStore({
  8.  
    reducer: {
  9.  
    counterReducer,
  10.  
    nameReducer
  11.  
    }
  12.  
    })
  13.  
     
  14.  
    // 最终导出的store, 也就是index中的store,
  15.  
    // 是包含了counterReducer 和 nameReducer在内的store
  16.  
    export default store
学新通

4. 各个状态store的配置, 这里就使用一个来举例子, 写法都一致, 以nameReducer来举例子

在rt中导出了一个createSlice, 从定义的名字上来看, slice意为 “片段、部分”, 就是创建一个局部的store, 最终将多个局部的片段来合并起来, 就是步骤3里面提到的。

name: 字符串,当前片段的名字, 需要定义一个name来区分各个片段;

initialState:对象, 初始定义的值, 也就是默认值, 当没有其他任务来改变的时候, 就会默认使用默认的值

reducer:对象, 定义修改initialState的值的方法, 修改initialState的值, 只能通过reducers内的方法来修改, (与vue的actions相似) 

代码如下

  1.  
    // hookRedux下的module下的name.js代码
  2.  
    import { createSlice} from "@reduxjs/toolkit";
  3.  
     
  4.  
    const nameSlice = createSlice({
  5.  
    name: "counter",
  6.  
    initialState: {
  7.  
    name: '天',
  8.  
    },
  9.  
    reducers: {
  10.  
    changeName(state, { payload }) {
  11.  
    state.name = payload;
  12.  
    },
  13.  
    },
  14.  
    });
  15.  
     
  16.  
    // 最终默认导出的就是当前片段的store
  17.  
    export default nameSlice.reducer;
  18.  
    // 定义导出的都是reducers里的方法
  19.  
    export const { changeName } = nameSlice.actions;
  20.  
     
  21.  
    // 注意!!! 这里的reducer和actions都是定义的, 不能自己修改
学新通

5.页面组件使用store, 首先确定一点, 这里说的store并不是片段的store、而是全局的store, 因为全局的store是要给所有的组件提供使用的; 其次, 当前的页面组件要用到全局store的某个片段store, 需要返回来使用

如下代码所示, 我要在当前的页面组件中获取到全局store的name片段store里的name, 就是步骤4里面定义的name, 并且对这个name进行修改, 将他修改为当前的时间。

5.1 先导入要修改的方法, 因为步骤4说了, 要修改initialState里的值, 只能通过方法来修改, 所以要引入changeName方法

5.2 react-redux提供了 {useSelector, useDispatch, shallowEqual} hook函数, 

        5.2.1 useSelector, 这是一个获取到全局store的hook函数, 在这里可以拿到当前页面组件所需要的store数据, 如下代码, useSelector的第一个回调函数的state参数, 该参数就是全局store里的所有数据, 也就是hookRedux下的index.js的默认导出的store里的reducer, 如下图所示学新通

 然后再通过解构获取到name, 这个name就可以在当前的页面组件中展示了;

        5.2.2 shallowEqual useSelector的第二个参数, 意为浅拷贝, 这个是一个优化处理的参数, 有了这个参数, 如果其他的数据修改, 并不会重新渲染当前页面组件, 举例子, 如果counterReducer里的某个数据变化了, 在这个页面组件中, 因为没有用到counter, 所以这里不会重新渲染, 这是一个优化的参数。

        5.2.3 useDispatch 之前多次提到, 要修改initialState里的数据, 要使用方法来修改, 这个方法已经被我们引入了, changeName方法。但这里不是直接调用, 而是要使用dispatch来派发调用, 该hook返回一个函数, 将要派发的方法传入即可。 如下代码所示。

当点击changeName的时候, 就会执行cn函数, cn派发了changeName函数, 修改了initialState里name的值, 当name变化了, 当前组件重新渲染, 对应的name也发生变化, 页面数据也就会改变

  1.  
    // hookPage下的 name.jsx 的代码
  2.  
    import React from "react";
  3.  
    import { changeName } from "../hookRedux/modules/name";
  4.  
    import {useSelector, useDispatch, shallowEqual} from 'react-redux'
  5.  
     
  6.  
    export default function Name() {
  7.  
    console.log('name')
  8.  
    const {name} = useSelector(state => {
  9.  
    return {
  10.  
    name: state.nameReducer.name,
  11.  
    }
  12.  
    }, shallowEqual)
  13.  
    const dispatch = useDispatch()
  14.  
     
  15.  
    function cn(value) {
  16.  
    dispatch(changeName(value))
  17.  
    }
  18.  
    return (
  19.  
    <div>
  20.  
    <p>{name}</p>
  21.  
    <p onClick={() => cn(new Date().toTimeString())}>changeName</p>
  22.  
    </div>
  23.  
    )
  24.  
    }
学新通

6. rt的异步操作

异步操作是放在 createAsyncThunk中来实现的, 同样的, 他也是一个rt中导出的函数,第一个字符串参数, 在你的调试器里显示标明当前的任务如图所示。

学新通

 第二个参数, 是一个回调函数, 一般在这里发起网络请求, 这个fetchHomeMultidataAction函数接受到的参数, 就会被放到value里去。 这里return 的数据将会在extraReducers中去

在extraReducers中对某个异步任务会触发3中不同状态的处理, pending 、fulfilled、 reject状态,一般只需要处理fulfilled、 将得到的数据放到state中去。

  1.  
    // hookRedux 下的module 下的name.js 的代码
  2.  
    import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
  3.  
    import axios from 'axios'
  4.  
     
  5.  
    // 外部组件调用这个异步函数即可
  6.  
    // 第二个回调函数参数, 是一个请求函数,一般在开发中是会import引入来使用的
  7.  
    export const fetchHomeMultidataAction =
  8.  
    // 这里的第一个字符串参数, 是在调试器里显示的当前在执行的任务的名字
  9.  
    createAsyncThunk('fetch/homemultidata', async (value) => {
  10.  
    const res = await axios.get('http://123.207.198xxxxxxxxx')
  11.  
    return res.data
  12.  
    })
  13.  
    const nameSlice = createSlice({
  14.  
    name: "counter",
  15.  
    initialState: {
  16.  
    name: '天',
  17.  
    banners: [],
  18.  
    recommends: [],
  19.  
    },
  20.  
    reducers: {
  21.  
    changeName(state, { payload }) {
  22.  
    state.name = payload;
  23.  
    },
  24.  
    },
  25.  
    // 异步的操作
  26.  
    extraReducers: {
  27.  
    // [fetchHomeMultidataAction.pending](state, action) {
  28.  
    // console.log('pedding')
  29.  
    // },
  30.  
    [fetchHomeMultidataAction.fulfilled](state, {payload}) {
  31.  
    state.banners = payload.data.banner.list
  32.  
    state.recommends = payload.data.recommend.list
  33.  
    },
  34.  
    // [fetchHomeMultidataAction.rejected](state, action) {
  35.  
    // console.log('reject')
  36.  
    // }
  37.  
    }
  38.  
    });
  39.  
     
  40.  
    export default nameSlice.reducer;
  41.  
    export const { changeName ,changeBanners,changeRecommends} = nameSlice.actions;
学新通

7. 页面组件中调用, 发起请求得到数据放到页面上。 从useSelector中结构出来的bannerList, 当派发了请求函数并执行之后, banners发生了变化, 当前页面组件重新执行, store数据渲染在页面上。

  1.  
    // hookPage下的name.jsx代码
  2.  
    import React from "react";
  3.  
    import { changeName,fetchHomeMultidataAction } from "../hookRedux/modules/name";
  4.  
    import {useSelector, useDispatch, shallowEqual} from 'react-redux'
  5.  
     
  6.  
    export default function Name() {
  7.  
    console.log('name')
  8.  
    const {name, bannerList} = useSelector(state => {
  9.  
    console.log(state, 'state')
  10.  
    return {
  11.  
    name: state.nameReducer.name,
  12.  
    bannerList: state.nameReducer.banners
  13.  
    }
  14.  
    }, shallowEqual)
  15.  
    const dispatch = useDispatch()
  16.  
     
  17.  
    function cn(value) {
  18.  
    dispatch(changeName(value))
  19.  
    }
  20.  
    // 在cb函数中, dispatch去派发请求的任务, 这样就能调用请求
  21.  
    function cb(value) {
  22.  
    // 当这一步执行完毕之后, store里的数据已经被修改了
  23.  
    dispatch(fetchHomeMultidataAction(value))
  24.  
    }
  25.  
     
  26.  
    return (
  27.  
    <div>
  28.  
    <p>{name}</p>
  29.  
    <p onClick={() => {cb('333')}}>changeBanners</p>
  30.  
    <p onClick={() => cn(new Date().toTimeString())}>changeName</p>
  31.  
    {
  32.  
    bannerList.map(item => {
  33.  
    return (<p key={item.acm}>{item.title}</p>)
  34.  
    })
  35.  
    }
  36.  
    </div>
  37.  
    )
  38.  
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfifeic
系列文章
更多 icon
同类精品
更多 icon
继续加载