基础工作流程
练习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;