redux

React的学习系列之Redux

Redux的官网

什么是 Redux ?

Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理!Redux 除了和 React 一起用外,还支持其它框架;它体小精悍(只有2kB,包括依赖),却有很强大的插件扩展生态!Redux 提供的模式和工具使您更容易理解应用程序中的状态何时、何地、为什么以及如何更新,以及当这些更改发生时,您的应用程序逻辑将如何表现!

什么时候应该用 Redux ?

  • 在应用的大量地方,都存在大量的状态
  • 应用状态会随着时间的推移而频繁更新
  • 更新该状态的逻辑可能很复杂
  • 中型和大型代码量的应用,很多人协同开发

Redux 库和工具

Redux 是一个小型的独立 JS 库, 但是它通常与其他几个包一起使用:React-Redux是我们的官方库,它让 React 组件与 Redux 有了交互,可以从 store 读取一些 state,可以通过 dispatch actions 来更新 store!Redux ToolkitRedux Toolkit 是我们推荐的编写 Redux 逻辑的方法。 它包含我们认为对于构建 Redux 应用程序必不可少的包和函数。 Redux Toolkit 构建在我们建议的最佳实践中,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序变得更加容易。Redux DevTools 拓展Redux DevTools Extension 可以显示 Redux 存储中状态随时间变化的历史记录,这允许您有效地调试应用程序。

Redux基础工作流

Redux 的原理

在这里插入图片描述

当我们知道了Redux的底层原理后,接下来我们来实现一个mini版本的Redux

mini-Redux的实现和应用
  1. 创建一个React的项目==(基于vite构构建)==

    yarn vite
    
    目录
    src                   
    ├─ assets             
    │  └─ react.svg       
    ├─ store              
    │  ├─ index.js                 
    ├─ App.css            
    ├─ App.jsx               
    ├─ index.css          
    └─ main.jsx 
    
  2. reduct中的createStore方法的解析

    方法中有一个state存储公共的状态,还有一个listeners事件池「集合」,已经三个方法和一个形参

    store/index.

    基础的结构

    export const createStore = reducer => {
      /* 存储公共状态 */
      let state;
      /* 存放事件池 */
      let listeners = [];
    
      /* 获取公共状态 */
      const getState = () => state;
    
      /* 像事件池添加组件更新的方法 */
      const subscribe = listener => {
      };
    
      /* 派发任务通知 reducer 执行 */
      const dispatch = action => {
      };
    
      return { getState, subscribe, dispatch };
    };
    

    首次执行createStore函数就会执行dispatch方法

    export const createStore = reducer => {
      /* 规则校验 */
      if (typeof reducer !== "function")
        throw new TypeError("reducer is not function");
      
      ...
    
      /* 派发任务通知 reducer 执行 */
      const dispatch = action => {
      };
      
      /* 唯一值 */
      const randomString = () =>
        Math.random().toString(32).substring(7).split("").join(".");
    
      /* 默认执行一次 dispatch派发,给公共状态赋值(初始值) */
      dispatch({
        type: `@@redux/INIT${randomString}`,
      });
    
      return { getState, subscribe, dispatch };
    };
    

    subscribe 方法的执行

    export const createStore = reducer => {
      ...
     
     	/* 向事件池添加组件更新的方法 */
      const subscribe = listener => {
        // 规则校验
        if (typeof listener !== "function")
          throw new TypeError("listener is not Function");
    
        // 添加组件更新的方法
        if (!listeners.includes(listener)) {
          listeners.push(listener);
        }
    
        // 移除组件更新的方法
        const unsubscribe = () => {
          let index = listeners.indexOf(listener);
          listeners.splice(index, 1);
        };
    
        return unsubscribe;
      };
      return { getState, subscribe, dispatch };
    };
    

    当事件行为执行时执行dispatch方法,更新公共状态并通知事件池中对应的方法执行完成后,移除方法

    const isPlainObject = obj => {
      let proto, Ctor;
      if (!obj || toString.call(obj) !== "[object Object]") return false;
      proto = Object.getPrototypeOf(obj);
      if (!proto) return true;
      Ctor = {}.hasOwnProperty.call(proto, "constructor") && proto.constructor;
      return typeof Ctor === "function" && Ctor === Object;
    };
    
    export const createStore = reducer => {
      ...
       /* 派发任务通知 reducer 执行 */
      const dispatch = action => {
        // 规则校验
        if (!isPlainObject(action)) throw new TypeError("action is not object");
        if (typeof action.type === undefined)
          throw new TypeError("Actions may not have an undefined 'type' property");
    
        // 执行reducer,传递:公共状态、行为对象,接收执行的返回值,替换公共状态
        state = reducer(state, action);
    
        // 当状态更更改,还需要把事件池中的方法执行
        listeners.forEach(listener => listener());
    
        return action;
      };
      return { getState, subscribe, dispatch };
    };
    

    到此就完成了一个简单的redux,完整的代码如下:

    const isPlainObject = obj => {
      let proto, Ctor;
      if (!obj || toString.call(obj) !== "[object Object]") return false;
      proto = Object.getPrototypeOf(obj);
      if (!proto) return true;
      Ctor = {}.hasOwnProperty.call(proto, "constructor") && proto.constructor;
      return typeof Ctor === "function" && Ctor === Object;
    };
    
    export const createStore = reducer => {
      /* 规则校验 */
      if (typeof reducer !== "function")
        throw new TypeError("reducer is not function");
    
      /* 存储公共状态 */
      let state;
      /* 存放事件池 */
      let listeners = [];
    
      /* 获取公共状态 */
      const getState = () => state;
    
      /* 像事件池添加组件更新的方法 */
      const subscribe = listener => {
        // 规则校验
        if (typeof listener !== "function")
          throw new TypeError("listener is not Function");
    
        // 添加组件更新的方法
        if (!listeners.includes(listener)) {
          listeners.push(listener);
        }
    
        // 移除组件更新的方法
        const unsubscribe = () => {
          let index = listeners.indexOf(listener);
          listeners.splice(index, 1);
        };
    
        return unsubscribe;
      };
    
      /* 派发任务通知 reducer 执行 */
      const dispatch = action => {
        // 规则校验
        if (!isPlainObject(action)) throw new TypeError("action is not object");
        if (typeof action.type === undefined)
          throw new TypeError("Actions may not have an undefined 'type' property");
    
        // 执行reducer,传递:公共状态、行为对象,接收执行的返回值,替换公共状态
        state = reducer(state, action);
    
        // 当状态更更改,还需要把事件池中的方法执行
        listeners.forEach(listener => listener());
    
        return action;
      };
    
      /* 唯一值 */
      const randomString = () =>
        Math.random().toString(32).substring(7).split("").join(".");
    
      /* 默认执行一次 dispatch派发,给公共状态赋值(初始值) */
      dispatch({
        type: `@@redux/INIT${randomString}`,
      });
    
      return { getState, subscribe, dispatch };
    };
    
  3. mini版本的Redux完成后我们在项目中应用

    1. 首先我们需要把公共状态放到全局上下文中,所有我们需要来创建一个上下文

      目录

      src                   
      ├─ assets             
      │  └─ react.svg       
      ├─ store              
      │  ├─ index.js                 
      ├─ App.css            
      ├─ App.jsx            
      ├─ + ThemeContext.js    
      ├─ index.css          
      └─ main.jsx 
      

      ThemeContext.js

      import { createContext } from 'react';
      const ThemeContext = createContext();
      export default ThemeContext;
      

      main.jsx

      import React from "react";
      import ReactDOM from "react-dom/client";
      import App from "./App";
      import "./index.css";
      import ThemeContext from "./ThemeContext";
      import store from "./store";
      
      ReactDOM.createRoot(document.getElementById("root")).render(
        <React.StrictMode>
          <ThemeContext.Provider
            value={{
              store,
            }}
          >
            <App />
          </ThemeContext.Provider>
        </React.StrictMode>
      )
      
    2. 创建三个组件来实现业务需求

      目录结构

      src                   
      ├─ assets             
      │  └─ react.svg       
      ├─ store              
      │  ├─ index.js               
      ├─ + views              
      │  + ├─ Vote.jsx        
      │  + ├─ VoteFooter.jsx  
      │  + └─ VoteMain.jsx    
      ├─ App.css            
      ├─ App.jsx            
      ├─ ThemeContext.js    
      ├─ index.css          
      └─ main.jsx  
      

      App.jsx

      import './App.css'
      import Vote from './views/Vote'
      
      function App() {
        return (
          <div className="App">
            <Vote />
          </div>  
        )
      }
      
      export default App
      

      Vote.jsx

      import VoteMain from "./VoteMain";
      import VoteFooter from "./VoteFooter";
      import ThemeContext from "../ThemeContext";
      import { useContext, useState, useEffect } from "react";
      
      const Vote = () => {
        const { store } = useContext(ThemeContext);
        const { supNum, oppNum } = store.getState();
        let [_, setRandom] = useState(0);
        useEffect(() => {
          const unsubscribe = store.subscribe(() => {
            setRandom(Math.random());
          });
        }, []);
      
        return (
          <>
            <header className="header">
              <h2 className="title">这个是我手写的一个 Mini Redux 状态管理</h2>
              <span className="num">{supNum + oppNum}人</span>
            </header>
            <VoteMain />
            <VoteFooter />
          </>
        );
      };
      
      export default Vote;
      

      VoteMain.jsx

      import { useContext } from "react";
      import ThemeContext from "../ThemeContext";
      
      const VoteFooter = () => {
        const { store } = useContext(ThemeContext);
      
        return (
          <div className="footer">
            <button
              onClick={() => {
                store.dispatch({
                  type: "VOTE_SUP",
                });
              }}
            >
              支持
            </button>
      
            <button
              onClick={() => {
                store.dispatch({
                  type: "VOTE_OPP",
                });
              }}
            >
              反对
            </button>
          </div>
        );
      };
      
      export default VoteFooter;
      

      VoteFooter.jsx

      import { useContext, useEffect, useState } from "react";
      import ThemeContext from "../ThemeContext";
      
      const VoteMain = () => {
        const { store } = useContext(ThemeContext);
        const { supNum, oppNum } = store.getState();
      
        const [_, setRandom] = useState(0)
      
        useEffect(() => {
          const unsubscribe = store.subscribe(() => {
            setRandom(Math.random());
          })
        }, [])
      
        return (
          <div className="main">
            <p>支持人数:{supNum}人</p>
            <p>反对人数:{oppNum}人</p>
          </div>
        );
      };
      
      export default VoteMain;
      
    3. 最后执行命令启动项

      yarn dev
      

      在这里插入图片描述

      到此我们就已经完成了一个mini-redux的实现和应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值