获取不到最新值
问题复现
function createS() {
let v = 1
const getV = () => v
const setV = (x: number) => v=x
return {
v, // v的值在return的一瞬间就定死了
getV,
setV
}
}
const s = createS()
s.setV(222)
console.log('***', s.v) // 1
console.log('+++', s.getV()) // 222
function createS() {
let v = 1
const getV = () => v
const setV = (x: number) => v=x
return {
v,
getV,
setV
}
}
const s = createS()
s.v = 999
console.log('***', s.v) // 999
console.log('+++', s.getV()) // 1
const o = {
v: 1,
getV() {
return this.v
},
setV(x: number) {
this.v = x
}
}
o.setV(333)
console.log(o.v) // 333
console.log(o.getV()); // 333
原因:
- 修改api.v 不会影响到
let v - 函数执行完毕后, 调用setV, 不会影响到
api.v
function createS() {
let v = 1
const getV = () => v
const setV = (x: number) => v=x
let api = {
v,
getV,
setV
}
return api
}
const s = createS()
s.v = 999
console.log('***', s.v) // 999
console.log('+++', s.getV()) // 1
creatStore
export const createStore = <S, A>(reducer: Function) => {
let state: S = reducer()
let fns: Function[] = []
const getState = () => state
const subscrible = (refresh: Function) => {
fns.push(refresh)
}
const dispatch = (action: A) => {
state = reducer(state, action) // 更新数据
fns.forEach(refresh => refresh()) // 触发渲染
}
return {
getState,
subscrible,
dispatch
}
}
增加一个取消订阅
export const createStore = <S, A>(reducer: Function) => {
let state: S = reducer()
let fns: Function[] = []
const getState = () => state
const subscrible = (refresh: Function) => {
fns.push(refresh)
return () => {
const index = fns.indexOf(refresh);
fns.splice(index, 1);
}
}
const dispatch = (action: A) => {
state = reducer(state, action) // 更新数据
fns.forEach(refresh => refresh()) // 触发渲染
}
return {
getState,
subscrible,
dispatch
}
}
react-redux
import { FC, createContext, useContext, useEffect, useState } from "react";
import { createStore } from "./redux";
import { useMounted } from "./useMount";
type S = ReturnType<typeof createStore> // string
const StoreCtx = createContext<Partial<S>>({})
interface IProvider {
children: any
store: S
}
export const Provider: FC<IProvider> = ({store, children}) => {
return <StoreCtx.Provider value={store} >{children}</StoreCtx.Provider>
}
export const useDispatch = () => {
const store = useContext(StoreCtx) as S
return store.dispatch
}
export const useSelect = (cb: Function) => {
const store = useContext(StoreCtx) as S
const [_, render] = useState({})
const getValue = () => {
const state = store.getState()
const value = cb(state)
return value
}
useMounted(() => {
const unSub = store.subscrible(renderPro) // 订阅渲染函数
return () => unSub() // 取消订阅渲染函数
})
return getValue()
}
增加功能: 如果value没有变化就组件就不更新
import { FC, createContext, useContext, useEffect, useState } from "react";
import { createStore } from "./redux";
import { useMounted } from "./useMount";
type S = ReturnType<typeof createStore> // string
const StoreCtx = createContext<Partial<S>>({})
interface IProvider {
children: any
store: S
}
export const Provider: FC<IProvider> = ({store, children}) => {
return <StoreCtx.Provider value={store} >{children}</StoreCtx.Provider>
}
export const useDispatch = () => {
const store = useContext(StoreCtx) as S
return store.dispatch
}
export const useSelect = (cb: Function) => {
const store = useContext(StoreCtx) as S
const [_, render] = useState({})
const getValue = () => {
const state = store.getState()
const value = cb(state)
return value
}
const value = getValue()
// 如果value没有变化就不重新渲染
const renderPro = () => {
// useSelect执行前的value, render先执行, 触发渲染, useSelect才会执行
const newValue = getValue()
// useSelect执行时的value
const oldValue = value
if(oldValue !== newValue) render({})
}
useMounted(() => {
const unSub = store.subscrible(renderPro) // 订阅渲染函数
return () => unSub() // 取消订阅渲染函数
})
return value
}
中间件
中间件就是函数合成函数合成又叫洋葱模型/中间件函数合成可以帮我们把一个复杂的函数变成多个简单的函数
写法1
简化版
function run(middlewares) {
function dispatch(index) {
const fn = middlewares[index];
if (!fn) return;
const next = () => dispatch(index + 1)
fn(next);
}
dispatch(0);
}
const middlewares = [
(next) => {
console.log("start-1");
next();//此时 next = () => dispatch(1)
console.log("end-1");
},
(next) => {
console.log("start-2");
next();//此时 next = () => dispatch(2)
console.log("end-2");
},
(next) => {
console.log("start-3");
next();//此时 next = () => dispatch(3)
console.log("end-3");
}
];
run(middlewares);
传参版:
const run2 = (middlewares) => (arg) => {
const dispatch = (index) => {
const fn = middlewares[index];
if (!fn) return;
const next = () => dispatch(index + 1)
fn(next)(arg);
};
dispatch(0);
};
const middlewares2 = [
(next) => (arg) => {
console.log(arg, "start-1");
next();
console.log(arg, "end-1");
},
(next) => (arg) => {
console.log(arg, "start-2");
next();
console.log(arg, "end-2");
},
(next) => (arg) => {
console.log(arg, "start-3");
next();
console.log(arg, "end-3");
}
];
run2(middlewares2)("context");
缺点
- 如果
arg是基础数据类型 arg将无法被修改
原因
let a = 1
function fn(a) {
a = 2
}
fn(a)
console.log(a) // 1
let a = {age: 1}
function fn(a) {
a.age = 2
}
fn(a)
console.log(a) // {age: 2}
完成版
arg值可修改
const middlewares3 = [
(next) => (ctx) => {
console.log(ctx, "start-1");
next(ctx+1);
console.log(ctx, "end-1");
},
(next) => (ctx) => {
console.log(ctx, "start-2");
next(ctx+10);
console.log(ctx, "end-2");
},
(next) => (ctx) => {
console.log(ctx, "start-3");
next(ctx);
console.log(ctx, "end-3");
}
];
const run3 = (midwares: Function[]) => (ctx: any) => {
/**
* @param i 选择midwares第i个函数执行
* @param arg 第i个函数执行时需要的参数
*/
const chooseFnRun = (i: number, ctx: any) => {
const fn = midwares[i]
if (!fn) return
const next = (ctx: any) => chooseFnRun(i + 1, ctx)
fn(next)(ctx)
}
chooseFnRun(0, ctx)
}
run3(middlewares3)(100)
// 打印:
// 100 start-1
// 101 start-2
// 111 start-3
// 111 end-3
// 101 end-2
// 100 end-1
写法2
无参版
const tasks = [
(next) => {
console.log("start-1");
next();
console.log("end-1");
},
(next) => {
console.log("start-2");
next();
console.log("end-2");
},
(next) => {
console.log("start-3");
next();
console.log("end-3");
}
];
let curIndex = 0
const runTask = () => {
const task = tasks[curIndex]
if(task) task(next)
else curIndex=0
}
const next = () => {
curIndex++
runTask()
}
runTask()
传参版
const tasks = [
(next) => (ctx) => {
console.log(ctx, "start-1");
next(ctx+1);
console.log(ctx, "end-1");
},
(next) => (ctx) => {
console.log(ctx, "start-2");
next(ctx+10);
console.log(ctx, "end-2");
},
(next) => (ctx) => {
console.log(ctx, "start-3");
next(ctx);
console.log(ctx, "end-3");
}
];
let curIndex = 0
const runTask = (ctx) => {
const task = tasks[curIndex]
if(task) task(next)(ctx)
else curIndex=0
}
const next = (ctx: any) => {
curIndex++
runTask(ctx)
}
runTask(10)
优化
const tasks = [
(next) => (ctx) => {
console.log(ctx, "start-1");
next(ctx+1);
console.log(ctx, "end-1");
},
(next) => (ctx) => {
console.log(ctx, "start-2");
next(ctx+10);
console.log(ctx, "end-2");
},
(next) => (ctx) => {
console.log(ctx, "start-3");
next(ctx);
console.log(ctx, "end-3");
}
];
function run(tasks, ctx) {
let curIndex = 0
runTask(ctx)
function runTask(ctx) {
const task = tasks[curIndex]
if(!task) return
task(next)(ctx)
}
function next(ctx) {
curIndex++
runTask(ctx)
}
}
run(tasks, 10)
写法3
基础版
const chain = [
(args) => {
console.log(args, "---f1");
return args;
},
(args) => {
console.log(args, "---f2");
return args;
},
(args) => {
console.log(args, "---f3");
return args;
}
];
const compose3 = (...fns) => {
if (fns.length === 0) return (arg) => arg;
if (fns.length === 1) return fns[0];
return fns.reduce((a, b) => (...arg) => a(b(...arg)));
};
compose3(...chain)("aaa");
// 打印
// ---f3
// ---f2
// ---f1
加强版
const f = [
(next) => (arg) => {
console.log(arg, "--- start 1");
next(arg);
console.log(arg, "--- end 1");
},
(next) => (arg) => {
console.log(arg, "--- start 2");
next(arg);
console.log(arg, "--- end 2");
},
(next) => (arg) => {
console.log(arg, "--- start 3");
next(arg);
console.log(arg, "--- end 3");
}
];
// compose4函数就定义了两个函数, a和b
// let a = (...arg) => f[0](f[1](...arg))
// let b = (...arg) => a(f[2](...arg))
const compose4 = (...fns) => {
if (fns.length === 0) return (arg) => arg;
if (fns.length === 1) return fns[0];
return fns.reduce((a, b) => (...arg) => a(b(...arg)));
};
//相当于执行: b(() => console.log("aaa"))("参数");
compose4(...f)(() => console.log("aaa"))("参数");
// 打印
// 参数--- start 1
// 参数--- start 2
// 参数--- start 3
// aaa
// 参数--- end 3
// 参数--- end 2
// 参数--- end 1
写法4
const mdws = [
(next) => (arg) => {
console.log(arg, "start-1", "写法二");
next(arg);
console.log(arg, "end-1", "写法二");
},
(next) => (arg) => {
console.log(arg, "start-2", "写法二");
next(arg);
console.log(arg, "end-2", "写法二");
},
(next) => (arg) => {
console.log(arg, "start-3", "写法二");
next(arg);
console.log(arg, "end-3", "写法二");
}
];
const compose = (mdws) => (fn) => {
mdws.reverse();
mdws.map((mdw) => (fn = mdw(fn)));
return fn;
};
compose(mdws)((arg) => console.log(arg, "center--- 写法二"))("jack");