需求
订阅,取消订阅。
发出更新请求。
实现过程
1,首先,createStore是个函数,返回总Store对象。
有订阅方法,发出请求方法,和获取状态三个函数。
export default function (reducer, initState) {
function subscribe(fn) {
}
function dispatch(action) {
}
function getState() {
}
return {
subscribe,
dispatch,
getState
}
}
2,预处理。
保存参数,各种初始化。
//副本
let cReducer = reducer
let cState = initState
//订阅列表
let cListeners
let nListeners = cListeners = []
//状态标记
let isDispatching = false
let isSubscribed = false
//照搬
function ensureCanMutateNextListeners() {
if (nListeners === cListeners) {
nListeners = cListeners.slice()
}
}
3,实现订阅
//订阅
function subscribe(fn) {
if (isDispatching) {
return
}
isSubscribed = true
ensureCanMutateNextListeners()
nListeners.push(fn)
//取消
return function () {
if (isDispatching) {
return
}
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nListeners.indexOf(fn)
nListeners.splice(index, 1)
}
}
4,实现更新
function dispatch(action) {
if (isDispatching) {
return
}
if (typeof action === "object") {
try {
isDispatching = true
cState = cReducer(cState, action)
} finally {
isDispatching = false
}
const listeners = cListeners = nListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
} else if (typeof action === "function") {
action(dispatch)
}
}
5,获取状态
function getState() {
return cState;
}
全部代码
export default function (reducer, initState) {
//副本
let cReducer = reducer
let cState = initState
//订阅列表
let cListeners
let nListeners = cListeners = []
//状态标记
let isDispatching = false
let isSubscribed = false
//照搬
function ensureCanMutateNextListeners() {
if (nListeners === cListeners) {
nListeners = cListeners.slice()
}
}
//订阅
function subscribe(fn) {
if (isDispatching) {
return
}
isSubscribed = true
ensureCanMutateNextListeners()
nListeners.push(fn)
//取消
return function () {
if (isDispatching) {
return
}
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nListeners.indexOf(fn)
nListeners.splice(index, 1)
}
}
function dispatch(action) {
if (isDispatching) {
return
}
if (typeof action === "object") {
try {
isDispatching = true
cState = cReducer(cState, action)
} finally {
isDispatching = false
}
const listeners = cListeners = nListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
} else if (typeof action === "function") {
action(dispatch)
}
}
function getState() {
return cState;
}
return {
subscribe,
dispatch,
getState
}
}
测试:计数器
Reducer
import createStore from "../../react-state";
let initState = {
count: 0
};
function CounterReducer(state, action) {
const {
type, amount} = action;
switch (type) {
case "Normal":
if (state.count + amount >= 0) {
return {
count: state.count + amount};
} else {
return state;
}
default:
return state;
}
}
export default createStore(CounterReducer, initState);
Action
export const Normal = v => ({
type: "Normal", amount: v
})
export const Async = (v, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(Normal(v));
}, time);
}
}
计数器
import {
Component} from "react";
import store from "./Reducer";
import {
Normal, Async} from "./Action";
export default class Counter extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
this.setState({
})
})
}
render() {
return <h1>{
store.getState().count}
<button onClick={
() => store.dispatch(Normal(1))}>同步加</button>
<button onClick={
() => store.dispatch(Normal(-1))}>同步减</button>
<button onClick={
() => store.dispatch(Async(1, 1000))}>异步加</button>
<button onClick={
() => store.dispatch(Async(-1, 1000))}>异步减</button>
<button onClick={
() => this.unsubscribe()}>取消订阅</button>
</h1>
}
}
效果:
简化
前端的JS是单线程模型,所以很多东西都可以不要。
export default function (reducer, initState) {
//副本
let cReducer = reducer
let cState = initState
//订阅列表
let cListeners = []
//订阅
function subscribe(fn) {
cListeners.push(fn)
//取消
return function () {
cListeners.splice(cListeners.indexOf(fn), 1)
}
}
function dispatch(action) {
if (typeof action === "object") {
cState = cReducer(cState, action)
for (let i = 0; i < cListeners.length; i++) {
cListeners[i]()
}
} else if (typeof action === "function") {
action(dispatch)
}
}
function getState() {
return cState;
}
return {
subscribe,
dispatch,
getState
}
}