-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
三少
committed
Jul 27, 2021
1 parent
7aa73e9
commit 4f271a1
Showing
7 changed files
with
436 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
*.log | ||
*.lock | ||
*.swp | ||
|
||
.github | ||
.cache | ||
.temp | ||
.idea | ||
.rn_temp | ||
.DS_Store | ||
|
||
CHANGELOG.md | ||
package-lock.json | ||
|
||
src | ||
node_modules | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# @antmjs/global-state | ||
|
||
> 全局UI数据缓存解决方案 | ||
## 为什么需要 | ||
|
||
我所理解的缓存分4类,1: 和UI无关的临时缓存;2: 和UI无关的本地缓存; 3: 和UI相关的全局缓存; 4: 和UI相关的局部缓存。本仓库解决的就是3的问题。 | ||
众所周知,这一类的解决方案其实有很多,比如redux、mobx,重点其实在于我们的项目适不适合这些比较重的解决方案。结合面试者的回答,有都走redux的,有请求走redux的,有自己约定的。其实都是在找一个临界点,而这个临界点结合业务以及一线小伙伴的理解都会产生不一样的结果,最终redux就成了一个黑洞。 | ||
我现在更倾向于少用,当然不是不用,而是可枚举的用(你很清楚里面存储了什么东西,和你使用@antmjs/cache这个库一样,你很清楚你定义了哪些key),而且由负责人维护,结合hooks,业务开发者只管取值。可以看看[模版](https://github.com/AntmJS/temptaro) | ||
|
||
## 安装 | ||
|
||
```bash | ||
yarn add @antmjs/global-state | ||
``` | ||
|
||
## 使用 | ||
|
||
```js | ||
import GlobalState from '@antmjs/state' | ||
|
||
const { | ||
Provider, | ||
useGlobalState, | ||
useGlobalLoading, | ||
useGlobalError, | ||
} = GlobalState({ user: {} }, { user: async function () { /** await getUser */ } }) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{ | ||
"name": "@antmjs/global-state", | ||
"version": "0.0.0", | ||
"main": "dist/index.js", | ||
"module": "dist/index.esm.js", | ||
"typings": "types/index.d.ts", | ||
"author": "三少 <hi_sanshao@outlook.com>", | ||
"description": "全局UI缓存解决方案", | ||
"license": "MIT", | ||
"publishConfig": { | ||
"access": "public", | ||
"registry": "http://registry.npmjs.org" | ||
}, | ||
"keywords": [ | ||
"cache", | ||
"globalState", | ||
"taro", | ||
"react" | ||
], | ||
"repository": { | ||
"type": "https", | ||
"url": "https://github.com/AntmJS/antm.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/AntmJS/antm/issues/new" | ||
}, | ||
"engines": { | ||
"node": ">=12", | ||
"npm": ">=6.4", | ||
"yarn": ">=1.22" | ||
}, | ||
"browserslist": [ | ||
"Chrome >= 35", | ||
"ChromeAndroid >= 35", | ||
"iOS >= 8", | ||
"Safari >= 8", | ||
"Android >= 4.1", | ||
"QQAndroid >= 4.1", | ||
"UCAndroid >= 4.1" | ||
], | ||
"scripts": { | ||
"_clean": "npx rimraf dist", | ||
"_real": "npx rollup -c ./rollup.config.js", | ||
"watch": "npx rollup -c ./rollup.config.js -w", | ||
"build": "run-s _clean _real", | ||
"test:watch": "", | ||
"test": "" | ||
}, | ||
"peerDependencies": { | ||
"@types/react": ">=17.0.0", | ||
"react": ">=17.0.0", | ||
"react-dom": ">=17.0.0" | ||
}, | ||
"dependencies": { | ||
"@babel/runtime-corejs3": "^7.14.7", | ||
"scheduler": "^0.20.2", | ||
"use-context-selector": "^1.3.7" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
const { resolve, join } = require('path') | ||
const { getBabelOutputPlugin } = require('@rollup/plugin-babel') | ||
const json = require('@rollup/plugin-json') | ||
const typescript = require('@rollup/plugin-typescript') | ||
const commonjs = require('@rollup/plugin-commonjs') | ||
const { nodeResolve } = require('@rollup/plugin-node-resolve') | ||
const cwd = process.cwd() | ||
|
||
const config = { | ||
input: join(cwd, 'src/index.ts'), | ||
output: [ | ||
{ | ||
file: join(cwd, 'dist/index.js'), | ||
format: 'cjs', | ||
exports: 'default', | ||
sourcemap: true, | ||
}, | ||
{ | ||
sourcemap: true, | ||
format: 'esm', | ||
exports: 'default', | ||
file: join(cwd, 'dist/index.esm.js'), | ||
}, | ||
], | ||
external: ['@babel/runtime-corejs3', 'react'], | ||
plugins: [ | ||
commonjs({ | ||
include: /\/node_modules\//, | ||
}), | ||
nodeResolve({ | ||
customResolveOptions: { | ||
moduleDirectories: ['node_modules'], | ||
}, | ||
}), | ||
json(), | ||
typescript({ | ||
allowSyntheticDefaultImports: true, | ||
jsx: true, | ||
}), | ||
getBabelOutputPlugin({ | ||
configFile: resolve(__dirname, '../../babel.config.js'), | ||
}), | ||
], | ||
} | ||
|
||
module.exports = [config] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { useRef, useState } from 'react' | ||
|
||
import { createContext, useContextSelector } from 'use-context-selector' | ||
import GlobalState from '../types/index.d' | ||
|
||
export default function < | ||
TData extends GlobalState.IAnyObject, | ||
TFetch extends GlobalState.IPromiseFunctionObject<TData>, | ||
>(data: TData, fetch: TFetch): GlobalState.IMethod<TData, TFetch> { | ||
// 全局数据使用的context | ||
const context = createContext(null) as React.Context< | ||
| null | ||
| [ | ||
GlobalState.StateOpt<{ [K in keyof TData]: TData[K] }>, | ||
React.Dispatch<React.SetStateAction<TData>>, | ||
] | ||
> | ||
|
||
// 远程请求数据状态变更使用的context | ||
const loadingContext = createContext(null) as React.Context< | ||
null | [Partial<{ [K in keyof TFetch]: boolean }>, any] | ||
> | ||
|
||
// 远程请求数据发生错误使用的context | ||
const errorContext = createContext(null) as React.Context< | ||
| null | ||
| [Partial<{ [K in keyof TFetch]: { code: string; message: string } }>, any] | ||
> | ||
|
||
// 更新全局数据使用的context | ||
const fetchContext = createContext({ | ||
fetchAndUpdate: (key: keyof TFetch, params?: any) => { | ||
console.error('调用失败,还未初始化', key, params) | ||
}, | ||
update: <T extends keyof TData>( | ||
key: T, | ||
value: Partial<GlobalState.StateOpt<{ [K in keyof TData]: TData[K] }>>[T], | ||
) => { | ||
console.error('调用失败,还未初始化', key, value) | ||
}, | ||
}) | ||
|
||
const Provider = ({ children }: any) => { | ||
const [state, setState] = useState(data) | ||
const [loading, setLoading] = useState({}) | ||
const [error, setError] = useState({}) | ||
const ins = useRef({ | ||
fetchAndUpdate: async (key: keyof TFetch, params?: any) => { | ||
if (fetch[key]) { | ||
const { data, error } = await fetch[key]!(params) | ||
if (!error) { | ||
setState((pre) => { | ||
return { ...pre, [key]: data } | ||
}) | ||
} | ||
} | ||
}, | ||
update: <T extends keyof TData>( | ||
key: T, | ||
value: Partial< | ||
GlobalState.StateOpt<{ [K in keyof TData]: TData[K] }> | ||
>[T], | ||
) => { | ||
console.error('调用失败,还未初始化', key, value) | ||
}, | ||
}) | ||
|
||
return ( | ||
<context.Provider value={[state, setState]}> | ||
<fetchContext.Provider value={ins.current}> | ||
<loadingContext.Provider value={[loading, setLoading]}> | ||
<errorContext.Provider value={[error, setError]}> | ||
{children} | ||
</errorContext.Provider> | ||
</loadingContext.Provider> | ||
</fetchContext.Provider> | ||
</context.Provider> | ||
) | ||
} | ||
|
||
function useGlobalState<T extends keyof TData>( | ||
key: T, | ||
): Partial<GlobalState.StateOpt<{ [K in keyof TData]: TData[K] }>>[T] { | ||
return useContextSelector(context, (v) => v?.[0][key]) | ||
} | ||
|
||
function useGlobalLoading<T extends keyof TData>( | ||
key?: T, | ||
): Partial<{ [K in keyof TFetch]: boolean }> { | ||
console.log(key) | ||
return {} | ||
} | ||
|
||
function useGlobalError<T extends keyof TData>( | ||
key?: T, | ||
): Partial<{ [K in keyof TFetch]: { code: string; message: string } }> { | ||
console.log(key) | ||
return {} | ||
} | ||
|
||
function useUpdate(): GlobalState.IUpdate<TData, TFetch> { | ||
return { | ||
fetchAndUpdate: async (key: keyof TFetch, params?: any) => { | ||
if (fetch[key]) { | ||
const { data, error } = await fetch[key]!(params) | ||
console.log(data, error) | ||
// if (!error) { | ||
// setState((pre) => { | ||
// return { ...pre, [key]: data } | ||
// }) | ||
// } | ||
} | ||
}, | ||
update: <T extends keyof TData>( | ||
key: T, | ||
value: Partial< | ||
GlobalState.StateOpt<{ [K in keyof TData]: TData[K] }> | ||
>[T], | ||
) => { | ||
console.error('调用失败,还未初始化', key, value) | ||
}, | ||
} | ||
} | ||
|
||
return { | ||
Provider, | ||
useGlobalState, | ||
useGlobalLoading, | ||
useGlobalError, | ||
useUpdate, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
declare namespace GlobalState { | ||
type Record<K extends keyof any, T> = { | ||
[P in K]: T | ||
} | ||
type IAnyObject = Record<string, any> | ||
type NoneEmptyArray<T> = [T, ...T[]] | ||
type IFunctionObject = Record<string, (arg?: any) => any> | ||
type IPromiseFunctionObject<TData> = Partial< | ||
{ | ||
[K in keyof TData]: ( | ||
params?: any, | ||
) => Promise<{ data: any; error?: { code: string; message: string } }> | ||
} | ||
> | ||
|
||
type StateOpt<T> = { | ||
[K in keyof T]: T[K] extends null | undefined | ||
? any | ||
: T[K] extends IAnyObject | ||
? T[K] & IAnyObject | ||
: T[K] | ||
} | ||
|
||
interface IUpdate< | ||
TData extends IAnyObject, | ||
TFetch extends IPromiseFunctionObject<TData>, | ||
> { | ||
fetchAndUpdate: (key: keyof TFetch, params?: any) => Promise<void> | ||
update: <T extends keyof TData>( | ||
key: T, | ||
value: Partial<StateOpt<{ [K in keyof TData]: TData[K] }>>[T], | ||
) => void | ||
} | ||
|
||
interface IMethod< | ||
TData extends IAnyObject, | ||
TFetch extends IPromiseFunctionObject<TData>, | ||
> { | ||
Provider: ({ children }: any) => JSX.Element | ||
useGlobalState: <T extends keyof TData>( | ||
key: T, | ||
) => Partial<StateOpt<{ [K in keyof TData]: TData[K] }>>[T] | ||
|
||
useGlobalLoading: <T extends keyof TData>( | ||
key?: T, | ||
) => Partial<{ [K in keyof TFetch]: boolean }> | ||
|
||
useGlobalError: <T extends keyof TData>( | ||
key?: T, | ||
) => Partial<{ [K in keyof TFetch]: { code: string; message: string } }> | ||
|
||
useUpdate: () => IUpdate<TData, TFetch> | ||
} | ||
} | ||
|
||
declare function GlobalState< | ||
TData extends IAnyObject, | ||
TFetch extends IPromiseFunctionObject<TData>, | ||
>(data: TData, fetch: TFetch): GlobalState.IMethod<TData, TFetch> | ||
|
||
export default GlobalState |
Oops, something went wrong.