redux的基础操作

102 阅读2分钟

基础工作流程

image.png

练习DEMO

store/index.js

import { createStore } from 'redux'

import _ from '@/assets/utils'

// REDUCER

let initial = {
  supNum: 0,

  oppNum: 0,
}

const reducer = function reducer(state = initial, action) {
  //防止直接操作原始状态对象向

  state = _.clone(true, state)

  // state:容器中的公共状态「第一次派发,没有公共状态的时候,我们让其等于初始状态」
  // action:每一次派发任务,传递进来的“行为对象”「必须要包含一个type属性(行为标识),其余可根据需求,传递其他信息进来」

  let { type, payload = 1 } = action
  // reducer中会基于派发的行为标识不同,修改不同的公共状态「reducer判断中用到的行为标识,一定要和每一次派发时,传递的行为标识对应上」

  switch (type) {
    case 'VOTE_SUP':
      state.supNum += payload

      break

    case 'VOTE_OPP':
      state.oppNum += payload

      break

    default:
  }

  return state
}

// 创建容器

const store = createStore(reducer)

export default store

 const clone = function clone(...params) {
        let target = params[0],
            deep = false,
            length = params.length,
            i = 1,
            isArray,
            isObject,
            result,
            treated;
        if (typeof target === "boolean" && length > 1) {
            deep = target;
            target = params[1];
            i = 2;
        }
        treated = params[i];
        if (!treated) treated = new Set();
        if (treated.has(target)) return target;
        treated.add(target);
        isArray = Array.isArray(target);
        isObject = isPlainObject(target);
        if (target == null) return target;
        if (!isArray && !isObject && !isFunction(target) && typeof target === "object") {
            try {
                return new target.constructor(target);
            } catch (_) {
                return target;
            }
        }
        if (!isArray && !isObject) return target;
        result = new target.constructor();
        each(target, (copy, name) => {
            if (deep) {
                result[name] = clone(deep, copy, treated);
                return;
            }
            result[name] = copy;
        });
        return result;
    };

src\index.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import '@/assets/reset.min.css';
import Vote from '@/views/Vote';
/* 注册STORE到上下文中 */
import store from './store';
import ThemeContext from './ThemeContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeContext.Provider
    value={{
      store
    }}>
    <Vote />
  </ThemeContext.Provider>
);

src\ThemeContext.js

// 把 store 放到上下文中,创建上下文对象
import { createContext } from 'react';
const ThemeContext = createContext();
export default ThemeContext;

src\views\Vote.jsx

import React, { useContext, useState, useEffect } from 'react';
import VoteMain from './VoteMain';
import VoteFooter from './VoteFooter';
import './Vote.less';
import ThemeContext from '@/ThemeContext';

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

    // 把让组件更新的办法加入到事件池中
    let [_, setRandom] = useState(0);
    useEffect(() => {
        const unsubscribe = store.subscribe(() => {
            setRandom(+new Date());
        });
        // unsubscribe() 可以把刚才注入到事件池中的方法移除
    }, []);

    return <div className="vote-box">
        <header className="header">
            <h2 className="title">React真的很不错!!</h2>
            <span className="num">{supNum + oppNum}人</span>
        </header>
        <VoteMain />
        <VoteFooter />
    </div>;
};
export default Vote;

src\views\VoteFooter.jsx

import React, { useContext } from 'react';
import ThemeContext from '@/ThemeContext';

const VoteFooter = function VoteFooter() {
    const { store } = useContext(ThemeContext);

    return <div className="footer">
        <button onClick={() => {
            store.dispatch({
                type: 'VOTE_SUP',
                payload: 10
            });
        }}>支持</button>

        <button onClick={() => {
            store.dispatch({
                type: 'VOTE_OPP'
            });
        }}>反对</button>
    </div>;
};
export default VoteFooter;