Article directory
need
Subscribe, unsubscribe.
Issue an update request.
Implementation process
1. First, createStore is a function that returns the total Store object.
There are three functions: subscribe method, send request method, and get status.
export default function (reducer, initState) {
function subscribe(fn) {
}
function dispatch(action) {
}
function getState() {
}
return {
subscribe,
dispatch,
getState
}
}
2. Preprocessing.
Save parameters, various initializations.
//副本
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. Implement subscription
//订阅
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. Realize the update
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. Get the status
function getState() {
return cState;
}
all code
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
}
}
Test: Counter
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);
}
}
counter
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>
}
}
Effect:
simplify
The front-end JS is a single-threaded model, so many things can be omitted.
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
}
}