生命周期:
这里的deps的生命周期,和 redux 一致。
const deps = {};
function create() {
deps.value = 'hello';
}
export default create;
createStore:这个API最终返回一个store对象,所有的功能都在这个对象上。
store.subscribe:订阅state的变化。当state变化时会执行回调,可以有多个subscribe,里面的回调依次执行。
store.dispatch:发出action的方法,每次dispatch一个action,都会reducer函数,生成新的state,然后执行subscribe注册的回调。
store.getState:返回当前的state。
多人开发的过程中,一不小心,就会把数据清空,或者勿修改了其他组件,副作用太大。
因此,我们需要制定一个 state 的 “修改计划”, 告诉store,我的修改计划是什么。
reducer : 修改store.changeState 方法,告诉他修改state的时候,按照我们的计划执行。
通过 reducer 来控制对数据的修改方式和预期。
处理副作用。
export default compose(...funcs) {
return funcs.reduce(
(a, b) => (...args) =>a(b(args));
);
}
function applyMiddleware = (...middlewares) =>{
createStore => (reducer, preloadedState) => {
//1.middleware即为我们上述的中间件,第一个参数是store
const store = createStore(reducer, preloadedState);
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args);
};
//2.chain中的item为接收next的中间件函数
const chain = middlewares.map(middleware => middleware(middlewareAPI));
//3.store.dispatch即为上述的next函数,在代码中,以next(action)进行执行
//4.将新的dispatch范湖出去,dispatch还是一个函数,函数的参数为
return {
...store, dispatch
}
}
}
react-redux 的核心:
//store/redux.js
export function createStore(reducer, initState) {
let state = initState;
let listeners = [];
// 订阅函数的实现
function subscribe(listener) {
listeners.push(listener);
}
//发布通知:不让你在dispatch时修改数据,只让你告诉我在dispatch时怎么修改数据
function dispatch(action) {
state = reducer(state, action);
//发布
for (let i = 0; i < listeners.length; i++) {
listeners[i]();
}
}
dispatch({
type: Symbol()
});
function getState() {
return state;
}
return { subscribe, dispatch, getState };
}
export function combineReducers(reducers) {
const keys = Object.keys(reducers);
return function combination(state = {}, action) {
const nextState = {};
//遍历一遍所有的reducers,整合成一个新的state
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const reducer = reducers[key];
const prev = state[key];
const next = reducer(prev, action);
nextState[key] = next;
}
return nextState;
}
}
// Provider.js
import React, { Component } from 'react'
import PropTypes from 'prop-types';
export default class Provider extends Component {
static childContextTypes = {
store: PropTypes.object
}
constructor(props, context) {
super(props, context);
this.store = props.store;
}
render() {
return this.props.children;
}
}
// context.js
import { createContext } from "react";
export default createContext();
// connect.jsx
import PropTypes from 'prop-types';
import React, { useContext, useState,useEffect } from 'react';
import ReduxContext from './context';
export const connect = (mapStateToProps, mapDispatchToProps) => Component => {
class Connect extends React.Component {
componentDidMount() {
this.context.subscribe(this.handleStoreChange.bind(this));
}
handleStoreChange() {
this.forceUpdate();
}
render() {
return (
<Component {...this.props} {...mapStateToProps(this.context.store.getState())} {...mapDispatchToProps(this.context.store.dispatch)} />
)
}
}
Connect.contextTypes = {
store: PropTypes
}
return Connect;
}
function Connect(props) {
const store = useContext(ReduxContext);
const [, setCount] = useState(true);
const forceUpdate = () => setCount(val => !val);
useEffect(() => store.subscribe(forceUpdate), []);
return (
<ReduxContext.Consumer>
{
store =>
<Component {...props} {...mapStateToProps(store.getState())} {...mapDispatchToProps(store.dispatch)} />
}
</ReduxContext.Consumer>
)
}
// store/index.js
import { combineReducers, createStore } from "./redux"
import { applyMiddleware } from 'redux';
import ReduxLogger from 'redux-logger';
// import { combineReducers, legacy_createStore as createStore } from "redux"
let initState = {
counter: { count: 0 },
info: { age: 12 }
}
function counterReducer(state, action) {
switch (action.type) {
case "ADD_COUNT":
return { count: state.count+1 }
case 'MINUS_COUNT':
return { count: state.count-1 }
default:
return state;
}
}
function infoReducer(state, action) {
switch (action.type) {
case 'ADD_COUNT':
return { age: state.age+1 }
case 'MINUNS_AGE':
return { age: state.age-1 }
default:
return state;
}
}
const reducers = combineReducers({
counter: counterReducer,
info: infoReducer
});
const store = createStore(reducers, initState);
export default store;
// index.js
// redux
// import { Provider } from 'react-redux';
import Provider from './store/Provider'
// import ReduxContext from './store/context';
import store from './store/index';
ReactDom.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
// App.js
// import create from './store/redux';
import Hello from './Hello';
function App() {
return (
<div className='App'>
<header className='App-header'>
hello~~
</header>
</div>
)
}
export default App;
// Hello.jsx
// import { connect } from 'react-redux';
import { connect } from './store/connect';
function Hello(props) {
return (
<div>
{props.counter.count}
<button onClick={() => props.addCount()}>add</button>
</div>
)
}
const mapStateToProps = (state) => ({
counter: state.counter
});
const mapDispatchToProps = (dispatch) => {
return {
addCount: () => dispatch({
type: 'ADD_COUNT'
});
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Hello);
mobx 本身也只是一个响应数据状态变更的一个库。