Chore: code improvement

This commit is contained in:
Dreamacro 2019-09-30 11:11:40 +08:00
parent 8199612bc7
commit d66cf8f9fa
6 changed files with 514 additions and 343 deletions

730
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,17 +28,17 @@
"contributors:generate": "all-contributors generate"
},
"devDependencies": {
"@babel/cli": "^7.6.0",
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@babel/cli": "^7.6.2",
"@babel/core": "^7.6.2",
"@babel/preset-env": "^7.6.2",
"@babel/preset-react": "^7.0.0",
"@hot-loader/react-dom": "^16.9.0",
"@types/classnames": "^2.2.8",
"@types/lodash-es": "^4.17.3",
"@types/node": "^12.7.5",
"@types/react": "^16.9.2",
"@types/react-dom": "^16.9.0",
"@types/react-router-dom": "^4.3.5",
"@types/node": "^12.7.8",
"@types/react": "^16.9.3",
"@types/react-dom": "^16.9.1",
"@types/react-router-dom": "^5.1.0",
"@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.1",
"autoprefixer": "^9.6.1",
@ -52,22 +52,22 @@
"mini-css-extract-plugin": "^0.8.0",
"offline-plugin": "^5.0.7",
"postcss-loader": "^3.0.0",
"react-hot-loader": "^4.12.13",
"react-hot-loader": "^4.12.14",
"sass": "^1.22.12",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"stylelint": "^10.1.0",
"stylelint-config-standard": "^18.3.0",
"stylelint": "^11.0.0",
"stylelint-config-standard": "^19.0.0",
"stylelint-webpack-plugin": "^0.10.5",
"terser-webpack-plugin": "^2.0.1",
"terser-webpack-plugin": "^2.1.2",
"tslint": "^5.20.0",
"tslint-config-standard": "^8.0.1",
"tslint-loader": "^3.6.0",
"typescript": "^3.6.3",
"webpack": "^4.40.1",
"webpack-cli": "^3.3.8",
"webpack-dev-middleware": "^3.7.1",
"webpack-dev-server": "^3.8.0",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.8.1",
"webpack-merge": "^4.2.2",
"webpack-pwa-manifest": "^4.0.0"
},
@ -78,12 +78,12 @@
"eventemitter3": "^4.0.0",
"immer": "^4.0.0",
"lodash-es": "^4.17.15",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-router-dom": "^5.0.1",
"react": "^16.10.1",
"react-dom": "^16.10.1",
"react-router-dom": "^5.1.1",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
"unstated-next": "^1.1.0",
"use-immer": "^0.3.3"
"use-immer": "^0.3.4"
}
}

View File

@ -9,7 +9,7 @@ export default function ExternalController () {
const { t } = useTranslation('Settings')
const { data: info, update, fetch } = containers.useAPIInfo()
const { unauthorized: { hidden, visible } } = containers.useData()
const { value, setMulti, setSingle } = useObject({
const [value, set] = useObject({
hostname: '',
port: '',
secret: ''
@ -20,7 +20,7 @@ export default function ExternalController () {
}, [])
useEffect(() => {
setMulti({ hostname: info.hostname, port: info.port, secret: info.secret })
set({ hostname: info.hostname, port: info.port, secret: info.secret })
}, [info])
function handleOk () {
@ -46,7 +46,7 @@ export default function ExternalController () {
align="left"
inside={true}
value={value.hostname}
onChange={hostname => setSingle('hostname', hostname)}
onChange={hostname => set('hostname', hostname)}
/>
</Col>
</Row>
@ -57,7 +57,7 @@ export default function ExternalController () {
align="left"
inside={true}
value={value.port}
onChange={port => setSingle('port', port)}
onChange={port => set('port', port)}
/>
</Col>
</Row>
@ -68,7 +68,7 @@ export default function ExternalController () {
align="left"
inside={true}
value={value.secret}
onChange={secret => setSingle('secret', secret)}
onChange={secret => set('secret', secret)}
/>
</Col>
</Row>

View File

@ -15,7 +15,7 @@ export default function Settings () {
const { data: apiInfo } = containers.useAPIInfo()
const { useTranslation, setLang, lang } = containers.useI18n()
const { t } = useTranslation('Settings')
const { value: info, setSingle } = useObject({
const [info, set] = useObject({
socks5ProxyPort: 7891,
httpProxyPort: 7890,
isClashX: false
@ -24,13 +24,13 @@ export default function Settings () {
useEffect(() => {
fetch()
if (isClashX()) {
fetchClashXData().then(() => setSingle('isClashX', true))
fetchClashXData().then(() => set('isClashX', true))
}
}, [])
useEffect(() => {
setSingle('socks5ProxyPort', data.general.socksPort)
setSingle('httpProxyPort', data.general.port)
set('socks5ProxyPort', data.general.socksPort)
set('httpProxyPort', data.general.port)
}, [data])
async function handleProxyModeChange (mode: string) {
@ -58,7 +58,7 @@ export default function Settings () {
const [, err] = await to(updateConfig({ 'port': info.httpProxyPort }))
if (!err) {
await fetch()
setSingle('httpProxyPort', data.general.port)
set('httpProxyPort', data.general.port)
}
}
@ -66,7 +66,7 @@ export default function Settings () {
const [, err] = await to(updateConfig({ 'socks-port': info.socks5ProxyPort }))
if (!err) {
await fetch()
setSingle('socks5ProxyPort', data.general.socksPort)
set('socks5ProxyPort', data.general.socksPort)
}
}
@ -164,7 +164,7 @@ export default function Settings () {
<Col span={8}>
<Input
value={info.socks5ProxyPort}
onChange={socks5ProxyPort => setSingle('socks5ProxyPort', parseInt(socks5ProxyPort, 10))}
onChange={socks5ProxyPort => set('socks5ProxyPort', parseInt(socks5ProxyPort, 10))}
onBlur={handleSocksPortSave}
/>
</Col>
@ -178,7 +178,7 @@ export default function Settings () {
<Col span={8}>
<Input
value={info.httpProxyPort}
onChange={httpProxyPort => setSingle('httpProxyPort', parseInt(httpProxyPort, 10))}
onChange={httpProxyPort => set('httpProxyPort', parseInt(httpProxyPort, 10))}
onBlur={handleHttpPortSave}
/>
</Col>

View File

@ -3,43 +3,50 @@ import { useImmer } from 'use-immer'
import { createContainer } from 'unstated-next'
export function useObject<T extends object> (initialValue: T) {
let [copy, set] = useImmer(initialValue)
const [copy, rawSet] = useImmer(initialValue)
function setSingle<K extends keyof Draft<T>> (key: K, value: Draft<T>[K]) {
set(draft => {
draft[key] = value
})
function set<K extends keyof Draft<T>> (key: K, value: Draft<T>[K]): void
function set<K extends keyof Draft<T>> (data: Partial<T>): void
function set<K extends keyof Draft<T>> (f: (draft: Draft<T>) => void | T): void
function set<K extends keyof Draft<T>> (data: any, value?: Draft<T>[K]): void {
if (typeof data === 'string') {
rawSet(draft => {
const key = data as K
const v = value
draft[key] = v
})
} else if (typeof data === 'function') {
rawSet(data)
} else if (typeof data === 'object') {
rawSet((draft: Draft<T>) => {
const obj = data as Draft<T>
for (const key of Object.keys(obj)) {
const k = key as keyof Draft<T>
draft[k] = obj[k]
}
})
}
}
function setMulti<K extends keyof Draft<T>, U extends keyof T> (newValue: Partial<T>) {
set((draft: Draft<T>) => {
for (const key of Object.keys(newValue)) {
draft[key as K] = newValue[key as U] as any
}
})
}
return { value: copy, setSingle, setMulti, set }
return [copy, set] as [T, typeof set]
}
type containerFn<Value, State = void> = (initialState?: State) => Value
export function composeContainer<T, C = containerFn<T>, U = { [key: string]: C }> (mapping: U) {
export function composeContainer<T, C extends containerFn<T>, U extends { [key: string]: C }, K extends keyof U> (mapping: U) {
function Global () {
return Object.keys(mapping).reduce((obj, key) => {
obj[key] = mapping[key]()
obj[key as K] = mapping[key]()
return obj
}, {}) as { [K in keyof U]: T }
}, {} as { [K in keyof U]: T })
}
const allContainer = createContainer(Global)
return {
Provider: allContainer.Provider,
containers: Object.keys(mapping).reduce((obj, key) => {
obj[key] = function () {
return allContainer.useContainer()[key]
}
obj[key as K] = (() => allContainer.useContainer()[key]) as U[K]
return obj
}, {}) as { [K in keyof U]: U[K] }
}, {} as { [K in keyof U]: U[K] })
}
}

View File

@ -7,7 +7,7 @@ import { setLocalStorageItem, partition, to } from '@lib/helper'
import { useI18n } from '@i18n'
function useData () {
const { value: data, setSingle, setMulti, set } = useObject<Models.Data>({
const [data, set] = useObject<Models.Data>({
general: {},
proxy: [],
proxyGroup: [],
@ -32,7 +32,7 @@ function useData () {
const [{ data: general }, rawProxies, rules] = resp
setSingle('general', {
set('general', {
port: general.port,
socksPort: general['socks-port'],
redirPort: general['redir-port'],
@ -51,7 +51,7 @@ function useData () {
.map(key => ({ ...rawProxies.data.proxies[key], name: key }))
const [proxy, groups] = partition(proxies, proxy => !policyGroup.has(proxy.type))
setMulti({
set({
proxy: proxy as API.Proxy[],
proxyGroup: general.mode === 'Global' ? [proxyList] : groups as API.Group[],
rules: rules.data.rules
@ -71,7 +71,7 @@ function useData () {
}
function useAPIInfo () {
const { value: data, setMulti } = useObject<Models.APIInfo>({
const [data, set] = useObject<Models.APIInfo>({
hostname: '127.0.0.1',
port: '9090',
secret: ''
@ -79,7 +79,7 @@ function useAPIInfo () {
async function fetch () {
const info = await API.getExternalControllerConfig()
setMulti({ ...info })
set({ ...info })
}
async function update (info: Models.APIInfo) {
@ -94,7 +94,7 @@ function useAPIInfo () {
}
function useClashXData () {
const { value: data, setMulti } = useObject<Models.ClashXData>({
const [data, set] = useObject<Models.ClashXData>({
startAtLogin: false,
systemProxy: false
})
@ -103,7 +103,7 @@ function useClashXData () {
const startAtLogin = await jsBridge.getStartAtLogin()
const systemProxy = await jsBridge.isSystemProxySet()
setMulti({ startAtLogin, systemProxy })
set({ startAtLogin, systemProxy })
}
return { data, fetch }