Skip to content

Commit

Permalink
feat(react): 新增 createGlobalState
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Jun 18, 2020
1 parent 12b886d commit 037adcc
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 1 deletion.
84 changes: 84 additions & 0 deletions src/react/createGlobalState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { act, renderHook } from '@testing-library/react-hooks'
import { createGlobalState } from './createGlobalState'

describe('createGlobalState', () => {
describe('有初始值', () => {
const useGlobalName = createGlobalState('')

test('getState 正常', () => {
expect(useGlobalName.getState()).toBe('')
})

test('setState 正常', () => {
useGlobalName.setState('Jay')
expect(useGlobalName.getState()).toBe('Jay')
})

test('跨组件状态共享正常', () => {
const { result: result1 } = renderHook(() => useGlobalName())
const { result: result2 } = renderHook(() => useGlobalName())
const { result: result3 } = renderHook(() => useGlobalName())

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])

act(() => result2.current[1]('Fong'))

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])
.toBe('Fong')

act(() => result1.current[1](() => 'jj'))

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])
.toBe('jj')
})
})

describe('无初始值', () => {
const useGlobalName = createGlobalState<string>()

test('getState 正常', () => {
expect(useGlobalName.getState()).toBe(undefined)
})

test('setState 正常', () => {
useGlobalName.setState('Jay')
expect(useGlobalName.getState()).toBe('Jay')
})

test('跨组件状态共享正常', () => {
const { result: result1 } = renderHook(() => useGlobalName())
const { result: result2 } = renderHook(() => useGlobalName())
const { result: result3 } = renderHook(() => useGlobalName())

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])

act(() => result2.current[1]('Fong'))

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])
.toBe('Fong')

act(() => result1.current[1](() => 'jj'))

expect(useGlobalName.getState())
.toBe(result1.current[0])
.toBe(result2.current[0])
.toBe(result3.current[0])
.toBe('jj')
})
})
})
47 changes: 47 additions & 0 deletions src/react/createGlobalState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react'

export interface CreateGlobalStateResult<S> {
(): readonly [S, Dispatch<SetStateAction<S>>]
getState(): S
setState(nextState: SetStateAction<S>): void
}

export function createGlobalState<S>(): CreateGlobalStateResult<S | undefined>

export function createGlobalState<S>(
initialState: S,
): CreateGlobalStateResult<S>

export function createGlobalState<S>(
initialState?: S,
): CreateGlobalStateResult<S | undefined> {
let currentState: S | undefined = initialState
const stateSetters: Dispatch<SetStateAction<S | undefined>>[] = []
const getState: () => S | undefined = () => currentState
const setState: Dispatch<SetStateAction<S | undefined>> = nextState => {
if (typeof nextState === 'function') {
nextState = (nextState as any)(currentState)
}
currentState = nextState as any
for (const setter of stateSetters) {
setter(nextState)
}
}
const useGlobalState: CreateGlobalStateResult<S | undefined> = (() => {
const [globalState, setGlobalState] = useState(currentState)
useEffect(() => {
stateSetters.push(setGlobalState)
return () => {
const i = stateSetters.indexOf(setGlobalState)
/* istanbul ignore else */
if (i !== -1) {
stateSetters.splice(i, 1)
}
}
}, [])
return [globalState, setState] as const
}) as any
useGlobalState.getState = getState
useGlobalState.setState = setState
return useGlobalState
}
3 changes: 2 additions & 1 deletion src/react/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

export * from 'react-use'

// @index(['./**/*.ts', '!./**/*.test.*', '!./useToggle.*'], f => `export * from '${f.path}'`)
// @index(['./**/*.ts', '!./**/*.test.*', '!./{useToggle,createGlobalState}.*'], f => `export * from '${f.path}'`)
export * from './useClassName'
export * from './useLoadMore'
export * from './useReachBottom'
Expand All @@ -18,3 +18,4 @@ export * from './useValidator'

// 与 react-use 同名的应手动指定导出的模块
export { useToggle, UseToggleResult } from './useToggle'
export { createGlobalState, CreateGlobalStateResult } from './createGlobalState'

0 comments on commit 037adcc

Please sign in to comment.