redux的基础操作和思想

 后端   大苹果   2023-12-01 22:01   315

Redux相关源码:可以理解为主,但不要求一定都会写

redux不会,虽然也有一些其他的替代方案:mobx,但是基本可以宣告react阵亡了

VUE->Vuex

Redux生态圈中的知识

  • redux react-redux redux中间件
  • mobx 类的装饰器
  • react-router-dom v5/v6
  • redux-saga/dva/umi
  • fetch及其二次封装
  • antd pro

复合组件通信:

  1. 父子通信“具备相同父亲的兄弟组件”:props属性 “基于ref”
  2. 祖先和后代“具备相同祖先的平行组件”:context上下文

redux/react-redux 也是实现组件之间的通信技术“插件”

不管任何类型的组件,都可以基于这种方法,实现组件通信

公共状态管理方案

后期实战开发中,父子组件一般是基于: props/ref/redux其余组件的通信一般都是基于redux管理的

image.png

image.png

三个组件中,都需要用到创建的store容器

我在根组件中,导入store,把其放在上下文中,后期其他组件需要,只要是它的后代组件,则直接获取使用即可!!!

redux的使用

image.png

import {  createStore } from 'redux';
/* 管理员:修改STORE容器中的公共状态 */

let initial = {
    supNum: 10,
    oppNum: 5
}

const reducer = function reducer(state = initial, action) {
    // state: 存储STORE容器中的公共状态“最开始没有的时候,赋值初始状态值initial”
    // action: 每一次基于dispatch派发的时候,传递进来的行为对象“要求必须具备type属性,存储派发的行为标识”
    // 接下来我们需要基于派发的行为标识,修改STORE容器中的公共状态信息
    switch(action.type) {
        case "VOTE_SUP":
            break;
        case "VOTE_OPP":
            break;
        default:

    }

    // return的内容,会整体替换STORE容器中的内容
    return state;
}

// 创建STORE公共容器
const store = createStore(reducer);

store.dispatch({
    type: "VOTE_SUP",
    step: 10
});

export default store;

image.png

image.png

image.png

通过上下文获取store

  • store.js
import {  createStore } from 'redux';
/* 管理员:修改STORE容器中的公共状态 */

let initial = {
    supNum: 10,
    oppNum: 5
}

const reducer = function reducer(state = initial, action) {
    // state: 存储STORE容器中的公共状态“最开始没有的时候,赋值初始状态值initial”
    // action: 每一次基于dispatch派发的时候,传递进来的行为对象“要求必须具备type属性,存储派发的行为标识”
    // 接下来我们需要基于派发的行为标识,修改STORE容器中的公共状态信息
    switch(action.type) {
        case "VOTE_SUP":
            state.supNum++;
            break;
        case "VOTE_OPP":
            state.oppNum++;
            break;
        default:

    }

    // return的内容,会整体替换STORE容器中的内容
    return state;
}

// 创建STORE公共容器
const store = createStore(reducer);
export default store;
  • index.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.sass';
import Vote from './views/Vote';
import { ConfigProvider } from 'antd';
import store from './store';
import ThemeContext from './ThemeContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ConfigProvider>
    <ThemeContext.Provider value={
      store
    }>
      <Vote></Vote>
    </ThemeContext.Provider>
  </ConfigProvider>
);
  • vote.jsx
import React, { useContext, useEffect, useState } from "react";
import "./Vote.sass";
import VoteMain from "./VoteMain";
import VoteFooter from "./VoteFooter";
import ThemeContext from "../ThemeContext";

function Vote()  {
    const { store } = useContext(ThemeContext);
    const { supNum, oppNum } = store.getState();

    // 组件第一次渲染完毕之后,把组件更新的方法,放在STORE的事件池中

    // const [ num, setNum ] = useState(0);

    // const update = () => {
    //     setNum(num + 1);
    // }

    // useEffect(() => {
    //     // let unsubscribe = store.subscribe(让组件更新的方法);
    //     //  把让组件更新的方法放在STORE的事件池中
    //     //  返回的unsubscribe方法执行,可以把刚才放入事件池中的方法移除掉
    //     let unsubscribe = store.subscribe(update);
    //     return  () => {
    //         unsubscribe();
    //     }
    // }, [ num ])

    const [ _, setNum ] = useState(0);

    useEffect(() => {
        // let unsubscribe = store.subscribe(让组件更新的方法);
        //  把让组件更新的方法放在STORE的事件池中
        //  返回的unsubscribe方法执行,可以把刚才放入事件池中的方法移除掉
        store.subscribe(() => {
            setNum(new Date().valueOf());
        });
        // return  () => {
        //     unsubscribe();
        // }
    }, [])

    return  <div className="vote-box">
        <div className="header">
            <h2 className="title">
                React是很棒的前端框架
            </h2>
            <span className="num"> { supNum + oppNum } </span>
        </div>
        <VoteMain supNum={supNum} oppNum={oppNum} ></VoteMain>
        <VoteFooter ></VoteFooter>
    </div>
}

export default Vote;
  • VoteMain.jsx
import React from "react";
import ThemeContext from "../ThemeContext";

class VoteMain extends React.Component {
    static contextType = ThemeContext;

    render() {
        const {store} = this.context;
        const { supNum, oppNum } = store.getState();
        let ratio = "--";
        let total = supNum + oppNum;
        if (total > 0) {
            ratio = (supNum / total).toFixed(2);
        }
        return <div className="main">
            <p>支持人数:{ supNum }</p>
            <p>反对人数:{ oppNum }</p>
            <p>支持比率:{ ratio }</p>
        </div>
    }

    componentDidMount() {
        const { store } = this.context;
        store.subscribe( () => {
            this.forceUpdate();
        });
    }
}
export default VoteMain;
  • VoteFooter.jsx
import React, { useContext } from "react";
import { Button } from "antd"
import ThemeContext from "../ThemeContext";

function VoteFooter() {
    const { store } = useContext(ThemeContext);
    return <div className="footer">
        <Button onClick={ () => {
            store.dispatch({
                type: "VOTE_SUP"
            })
        }} type="primary">支持</Button>
        <Button onClick={() => {
            store.dispatch({
                type: "VOTE_OPP"
            })
        }} type="primary" danger>反对</Button>
    </div>
}
export default VoteFooter;

类组件的更新

image.png

image.png

image.png

image.png

image.png

总结:
redux具体的代码编写顺序
1.创建store,规划出reducer r当中的业务处理逻辑可以后续不断完善,但是最开始reducer的这个架子需要先搭建取来J2.在入口中,基于上下文对象,把store放入到上下文中;需要用到store的组件,从上下文中获取!!
3.组件中基于store,完成公共状态的获取、和任务的派发
+使用到公共状态的组件,必须向store的事件池中加入让组件更新的办法,只有这样,才可以确保,公共状态改变,可以让组件更新,才可以获取最新的状态进行绑定!!