redux相信都不陌生(陌生的看中文文档:www.redux.org.cn/),它是 JavaScript 状态容器,提供可预测化的状态管理,你能够在React, Vue, Angular,服务端等地方使用。redux由三部分组成:Action, Reducer, Store,你须要编写的是Action和Reducer,好比最简单的计数器例子css
Action 部分react
// action type
const INCREMENT = "increment";
const DECREMENT = "decrement";
// action creator 也叫action 建立函数
function increment() {
return {
type: INCREMENT
}
}
function decrement() {
return {
type: DECREMENT
}
}
复制代码
Reducer 部分git
const initialState = {
count: 0
};
function countReducer(state = initialState, action) {
switch (action.type) {
case INCREMENT: {
return {
count: state.count + 1
}
}
case DECREMENT: {
return {
count: state.count - 1
}
}
default: {
return state
}
}
}复制代码
Store 部分github
const store = createStore(countReducer);
// 设置监听
store.subscribe(() => {
console.log(store.getState().count);
});
// 设置时间间隔去触发动做
setInterval(() => {
store.dispatch(increment());
}, 1000);复制代码
一个简单的redux应用就由上面三部分组成,重点关注createStore方法,由于算是它结合了Action和Reducer,并且也算是redux的核心,因此咱们尝试编写一个简单的createStore函数typescript
redux的createStore函数接收reducer,initialState两个参数,(middleware暂时先不考虑),而后返回一个对象,以下所示redux
{
getState () {},
dispatch (action) {},
subscribe (newListener) {},
replaceReducer (newReducer) {}
}复制代码
因此咱们很容易的就编写了如下createStore的简单实现代码浏览器
JavaScript架构
function createStore (reducer, initialState = reducer(void 0, { type: null })) {
let state = initialState; // 存储state
let currentReducer = reducer; // 存储当前的reducer
let listener = []; // 存储监听函数
return {
getState () {
return state
},
dispatch (action) {
state = currentReducer(state, action); // reducer用在这了
listener.forEach(cb => cb()); // 核心,每次调用dispatch时都调用监听的函数
return action;
},
subscribe (newListener) {
listener.push(newListener);
},
replaceReducer (newReducer) {
currentReducer = newReducer
}
}
}复制代码
typescript版app
export type Action = {
type: string,
[props: string]: any
};
export type ReducerType = (state: any, action: Action) => any;
export type Dispatch<T = Action> = (action: T) => any;
export type Store<T = any, E = Action> = {
getState: () => T,
dispatch: Dispatch<E>,
subscribe: (listener: Function) => void,
replaceReducer: (reducer: ReducerType) => void
};
export function createStore (reducer: ReducerType, initialState = reducer(void 0, { type: "" })): Store {
let state = initialState;
let currentReducer = reducer;
let listener: Array<Function> = [];
return {
getState () {
return state
},
dispatch (action: Action) {
state = currentReducer(state, action);
listener.forEach(cb => cb());
return action;
},
subscribe (newListener: Function) {
listener.push(newListener);
},
replaceReducer (newReducer: ReducerType) {
currentReducer = newReducer
}
}
}复制代码
好了,一个简易的createStore就完成了,固然跟redux的createStore仍是有必定差异的,好比没有中间件(这个后期在实现吧),没有异常处理等等dom
在react中,通常会使用React-Redux库,而最经常使用的就是<Provider/>组件和conncet方法了,接下了将简单实现Provider组件和conncet方法
基于typescript
import React from "react";
import { Store, Dispatch, Action } from "./createStore";
export interface ProviderProps {
store: Store
}
const StoreContext = React.createContext({
store: {}
});
// Provider组件实现,主要使用react 的Context
export class Provider extends React.Component<ProviderProps> {
constructor (props: any) {
super(props);
}
render (): React.ReactNode {
let value = {
store: this.props.store
};
// 利用Context 将store传到子组件中
return (
<StoreContext.Provider value={ value }>
{ this.props.children }
</StoreContext.Provider>
)
}
}
type mapStateType = (state: any) => any;
type mapDispatchType = (dispatch: (action: any) => any) => any;
// connect函数,其实就是高阶组件,利用了属性代理
export const connect = (mapStateToProps: mapStateType, mapDispatchToProps: mapDispatchType) =>
(Component: React.ElementType) =>
class NewComponent extends React.Component<any> {
state = {};
static contextType = StoreContext; // !!!
constructor (props: any, context: any) {
super(props);
}
componentDidMount (): void {
let store = this.context.store as Store; // 从context中获取store
store.subscribe(this.update); // 主要是设置监听器,当组件状态更新,将反应回store,使store也更新
this.update();
}
private update = () => {
let store = this.context.store as Store;
let state = store.getState();
const filterState = mapStateToProps(state); // !!
const actions = mapDispatchToProps(store.dispatch); // !!
this.setState({ ...filterState, ...actions });
};
render (): React.ReactNode {
return <Component { ...this.state }/>
}
};
复制代码
结合咱们实现的createStore以及Provider组件,connect函数,咱们来实现一个计数器的小例子
代码以下:
typescript
import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";
import { createStore, Action, Dispatch, Store } from "./createStore";
import { Provider, connect } from "./Provider";
// Action
const INCREMENT = "increment";
const DECREMENT = "decrement";
function increment (): Action {
return {
type: INCREMENT
}
}
function decrement (): Action {
return {
type: DECREMENT
}
}
// Reducer
type StoreState = {
value: number
};
function reducer (state: StoreState = { value: 0 }, action: Action) {
switch (action.type) {
case INCREMENT: {
return {
value: state.value + 1
}
}
case DECREMENT: {
return {
value: state.value - 1
}
}
default: {
return state
}
}
}
// Store
let CountStore = createStore(reducer);
type CountProps = {
count: number;
onDecrement: () => void;
onIncrement: () => void;
};
function Count (props: CountProps) {
return (
<div className="count-block">
<button className="increment-button" onClick={ props.onIncrement }>+</button>
<span className="text-block">{ props.count }</span>
<button className="decrement-button" onClick={ props.onDecrement }>-</button>
</div>
)
}
const mapStateToProps = (state: any) => ({
count: state.value
});
const mapDispatchToProps = (dispatch: Dispatch<Action>) => ({
onDecrement: () => dispatch(decrement()),
onIncrement: () => dispatch(increment())
});
const CountContainer: React.ElementType = connect(mapStateToProps, mapDispatchToProps)(Count);
type MyAppProps = {
store: Store
};
class MyApp extends React.Component<MyAppProps> {
constructor (props: MyAppProps) {
super(props);
}
render () {
return (
<Provider store={ this.props.store }>
<CountContainer/>
</Provider>
);
}
}
const render = () => ReactDOM.render(
<MyApp store={ CountStore }/>,
document.getElementById('root') as HTMLElement
);
CountStore.subscribe(render);
render();
复制代码
能够在浏览器上看效果
经过简单实现redux的createStore,以及react-redux的Provider, connect,能对redux的架构更加熟悉,知其因此然,因此用才会顺心顺手,固然上面只是一个简单的实现,若是要用于开发的话,固然建议直接用redux和react-redux,最后:因为代码是用typescript写的,因此转成JavaScript的话将类型定义给去了就行了(或者参考这里,建立一个typescript的React的项目: facebook.github.io/create-reac…)。