-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
自己的状态和reducer
let initState = {
count: 0
}
function reducer(state,action){
//如果没有初始值,那么就初始化一次
if(!state){
state=initState;
}
switch(action.type){
case 'INCREASE':
return {
...state,
count:state.count+1
}
case "DECREMENT":
return {
...state,
count:state.count-1
}
default:
return state;
}
}自己创建createStore
const createStore=function(reducer,initState){
let state=initState;
let listeners=[];
function subscribe(listener){
listeners.push(listener);
//退订
return function unsubscribe(listener){
const index=listeners.indexOf(listener);
listeners.splice(index,1)
}
}
function dispatch(action){
state=reducer(state,action);
for(let i=0;i<listeners.length;i++){
const listener=listeners[i];
listener();
}
}
function getState(){
return state;
}
/**
* 替换reducer
* @param {*} nextReDucer 要替换的reducer
*/
function replaceReducer(nextReDucer){
reducer=nextReDucer
dispatch({type:Symbol()});//刷一遍state状态
}
/**
* 所有reducer都不匹配,会初始化所有的state值
*/
dispatch({type:Symbol()});
return {
subscribe,dispatch,getState
}
}合并reducer方法
/**
* 合并
* @param {*} reducers 传入reducer数据结构类似于{
counter: counterReducer,
info: InfoReducer
}
*/
function combinReducers(reducers){
const reducerKeys=Object.keys(reducers);
return function combination(state={},action){//返回一个新的reducer ,对所有传入的state和action重新做处理
const nextState={};//定义新的state
//遍历所有reducer,每个reducer都会返回相关的数据,处理之后,返回新数据,没有相关联的,就返回之前的数据
for(let i=0;i<reducerKeys.length;i++){
const key=reducerKeys[i];//reducer name
const reducer=reducers[key];//reducer
const preiousStateForKey=state[key];//传入state的某个值
const nextStateForKey=reducer(preiousStateForKey,action);
nextState[key]=nextStateForKey;//新构造出来一个
}
return nextState;//返回新的状态
}
}重点内容:中间件
//中间件是对dispatch的扩展
/**
* 比如记录日志
* 记录修改前的state,为什么修改,修改后的state
* 通过重写dispatch来实现
*
* const store=createStore(reducer);
* const next=store.dispatch;
*
* store.dispatch=(action)=>{
* console.log('this state',store.getState())
* next(action)
* console.log('next state',store.getState())
* }
*
* store.dispatch({
* type:'INCREMENT'
* })
*
* 输出日志
*
*/
/**
*
* 记录异常
*
* const store = createStore(reducer);
* const next = store.dispatch;
*
* store.dispatch=(action)=>{
* try{
* next(action)
* }catch(err){
* console.log(err)
* }
* }
*
*/
/**
* 如果两个功能都需要处理呢
*/
const store = createStore(reducer);
const next = store.dispatch;
//单独把日志提取出来
const loggerMiddleware = (action) => {
console.log('this state', store.getState());
console.log('action', action);
next(action);
console.log('next state', store.getState());
}
store.dispatch = (action) => {
try {
loggerMiddleware(action);
} catch (err) {
console.error('错误报告: ', err)
}
}
//把错误处理提取出来
// const exceptionMiddleware = (action) => {
// try {
// /*next(action)*/
// loggerMiddleware(action);
// } catch (err) {
// console.error('错误报告: ', err)
// }
// }
// store.dispatch = exceptionMiddleware;
/**
* 错误处理里面写定了日志,不可配,提取出来
*/
const exceptionMiddleware=(next)=>(action)=>{
try{
next(action);//任意dispatch
}catch(err){
console.log(err);
}
}
store.dispatch=exceptionMiddleware(loggerMiddleware);
/**
* 扩展loggerMiddleware
*
* const loggerMiddleware=(next)=>(action)=>{
* console.log('this state',store.getState())
* console.log('action',action)
* next(action)
* console.log('next state',state.getState())
* }
*/
/**
* 两个中间件合作模式
*
*
* const store = createStore(reducer);
const next = store.dispatch;
const loggerMiddleware = (next) => (action) => {
console.log('this state', store.getState());
console.log('action', action);
next(action);
console.log('next state', store.getState());
}
const exceptionMiddleware = (next) => (action) => {
try {
next(action);
} catch (err) {
console.error('错误报告: ', err)
}
}
store.dispatch = exceptionMiddleware(loggerMiddleware(next));
*
*/
/**
* 单独把中间件拆分出来 ,里面包含了store,需要提取出来
*
*
* const store=creatStore(reducer)
* const next=store.dispatch;
*
* const loggerMiddleware=(store)=>(next)=>(action)=>{
* console.log('this state',store.getState());
* console.log('action',action)
*
* next(action)
* console.log('next state',store.getState)
* }
*
* const exceptMiddleware=(store)=>(next)=>(action)=>{
* try{
* next(action)
* }catch(err){
* console.log(err)
* }
* }
*
* const logger=loggerMiddleware(store);
* const exception=exceptionMiddleware(store);
* store.dispatch=exception(logger(next))
*/
/**
* 我们只需要构建出相关的中间件,其他的内部细节,通过creatStore扩展开来
*
* 期望实现
* const newCreatStore=applyMiddleware(exceptionMiddleware,timeMiddleware,loggerMiddleware)(creatStore)
* const store=newCreatStore(reducer);//return 新的store
*
* 实现 applyMiddleware
*
* const applyMiddleware=function(...middelwares){
* return function rewriteCreateStore(oldCreateStore){
* return function newCreatStore(reducer,initState){
* const store=oldCreateStore(reducer,initState);
*
* const chain=middelwares.map((middleware)=>middleware(store))
*
* let dispatch=store.dispatch;
*
* //实现 exception(time(logger(dispatch)))
* chian.reverse().map((middleware)=>{
* //更改dispatch
* dispatch=middleware(dispatch)
* })
* //重写
* store.dispatch=dispatch;
*
* return store
* }
* }
* }
*/
/**
* 现在会有两种createStore
*
* 没有中间件的creatStore
* import { createStore } from './redux';
* const store = createStore(reducer, initState);
*
*
* 有中间件的createStore
* const rewriteCreateStoreFunc = applyMiddleware(exceptionMiddleware, timeMiddleware, loggerMiddleware);
* const newCreateStore = rewriteCreateStoreFunc(createStore);
* const store = newCreateStore(reducer, initState);
*
*
* 为了统一起来,修改createStore方法
*
* const createStore=(reducer,initState,rewriteCreateStoreFunc)=>{
* if(rewriteCreateStoreFunc){
* const newCreateStore=rewriteCreateStoreFunc(createStore);
* return newCreateStore(reducer, initState)
* }
* 否则按照正常流程走
* }
*
*
*/
/**
* 最终用法
*
* const rewriteCreateStoreFunc = applyMiddleware(exceptionMiddleware, timeMiddleware, loggerMiddleware);
* const store = createStore(reducer, initState, rewriteCreateStoreFunc);
*/一些优化的地方
/**
* 目前中间件能够拿到store,通过store修改我们的东西,保持最小开放策略
* 传递给中间件的变成当前一个快照state
* 之前const chain = middlewares.map(middleware => middleware(store));
*
* 修改之后
* const simpleStore = { getState: store.getState };
* const chain = middlewares.map(middleware => middleware(simpleStore));
*
*/
/**
* compose
* applyMiddleware中,把 [A, B, C] 转换成 A(B(C(next))),是这样实现的
* const chain = [A, B, C];
* let dispatch = store.dispatch;
* chain.reverse().map(middleware => {
* dispatch = middleware(dispatch);
* });
*
* redux提供了一个方法compose
* const chain = [A, B, C];
* dispatch = compose(...chain)(store.dispatch)
*
* 内部实现
* export default function compose(...funcs) {
* if (funcs.length === 1) {
* return funcs[0]
* }
* return funcs.reduce((a, b) => (...args) => a(b(...args)))
* }
*/
/**
* 省略initState
* 有时候没有传initState,redux允许我们这么写
* const store = createStore(reducer, rewriteCreateStoreFunc);
* 内部实现
* const createStore=(reducer,initState,rewriteCreateStoreFunc)=>{
* if(typeof initState ==="function"){
* rewriteCreateStoreFunc=initState;
* initState=undefined;
* }
* ...
* }
*/
/**
* bindActionCreators
*
* 这只有在react-redux的connect实现中用到,
* 他通过闭包,把dispatch和actionCreator封装起来,让其他地方感觉不到redux的存在
*
* 通过普通方式来隐藏dispatch和actionCreator,注意最后两行代码
*
* const reducer=combineReducers({
* counter:counterRedcuer,
* info:infoReducer
* });
* const store=createStore(reducer);
*
*
* //返回action的函数叫做actionCreator
* function increment(){
* return {
* type:'INCREMENT'
* }
* }
*
* function setName(name){
* return {
* type:"SET_NAME",
* name:name
* }
* }
*
* const acrions={
* increment:function(){
* return store.dispatch(increment.apply(this,arguments))
* },
* setName:function(){
* return store.dispatch(setName.apply(this,arguments))
* }
* }
*
* ⚠️注意:我们可以把actions传到任何地方去,
* 其他地方实现加减的时候,根本不需要知道其他细节
*
* actions.increment();
* actions.setName('123')
* 发现有好多公共代码,在actions生成的过程中
* 希望可以直接调用:const actions=bindActionCreators({increment,setName},store.dispatch);
*
* 实现,通过闭包隐藏actionCreator和dispatch
*
* fucntion bindActionCreator(actionCreator,dispatch){
* return function(){
* return dispatch(actionCreator.apply(this,argument))
* }
* }
*
* export default function buindActionCreators(actionCreators,dispatch){
* if (typeof actionCreators === 'function') {
* return bindActionCreator(actionCreators, dispatch)
* }
* if (typeof actionCreators !== 'object' || actionCreators === null) {
* throw new Error()
* }
* const keys = Object.keys(actionCreators)
* const boundActionCreators = {}
* for (let i = 0; i < keys.length; i++) {
* const key = keys[i]
* const actionCreator = actionCreators[key]
* if (typeof actionCreator === 'function') {
* boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
* }
* }
* return boundActionCreators
* }
*/liang520liang520liang520liang520