Redux——手动实现一个Redux

需求

订阅,取消订阅。
发出更新请求。

实现过程

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
	}
}

猜你喜欢

转载自blog.csdn.net/qq_37284843/article/details/123655496