muya 2.0.0-beta.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -195
- package/cjs/index.js +1 -1
- package/esm/create-state.js +1 -0
- package/esm/create.js +1 -1
- package/esm/debug/development-tools.js +1 -1
- package/esm/index.js +1 -1
- package/esm/scheduler.js +1 -0
- package/esm/select.js +1 -0
- package/esm/use-value.js +1 -0
- package/esm/utils/__tests__/is.test.js +1 -1
- package/esm/utils/common.js +1 -1
- package/esm/utils/is.js +1 -1
- package/package.json +12 -12
- package/{packages/core → src}/__tests__/bench.test.tsx +3 -108
- package/src/__tests__/create.test.tsx +159 -0
- package/src/__tests__/scheduler.test.tsx +52 -0
- package/src/__tests__/select.test.tsx +127 -0
- package/src/__tests__/use-value.test.tsx +78 -0
- package/src/create-state.ts +50 -0
- package/src/create.ts +67 -0
- package/{packages/core → src}/debug/development-tools.ts +18 -3
- package/{packages/core → src}/index.ts +2 -1
- package/{packages/core/utils/global-scheduler.ts → src/scheduler.ts} +9 -3
- package/src/select.ts +69 -0
- package/src/types.ts +66 -0
- package/src/use-value.ts +22 -0
- package/{packages/core → src}/utils/__tests__/is.test.ts +24 -7
- package/{packages/core → src}/utils/common.ts +35 -10
- package/{packages/core → src}/utils/is.ts +5 -8
- package/types/create-state.d.ts +12 -0
- package/types/create.d.ts +6 -18
- package/types/debug/development-tools.d.ts +2 -9
- package/types/index.d.ts +2 -1
- package/types/{utils/scheduler.d.ts → scheduler.d.ts} +4 -1
- package/types/select.d.ts +10 -0
- package/types/types.d.ts +55 -5
- package/types/use-value.d.ts +2 -0
- package/types/utils/common.d.ts +6 -5
- package/types/utils/is.d.ts +3 -4
- package/esm/__tests__/create-async.test.js +0 -1
- package/esm/subscriber.js +0 -1
- package/esm/use.js +0 -1
- package/esm/utils/__tests__/context.test.js +0 -1
- package/esm/utils/__tests__/sub-memo.test.js +0 -1
- package/esm/utils/create-context.js +0 -1
- package/esm/utils/global-scheduler.js +0 -1
- package/esm/utils/scheduler.js +0 -1
- package/esm/utils/sub-memo.js +0 -1
- package/packages/core/__tests__/create-async.test.ts +0 -88
- package/packages/core/__tests__/create.test.tsx +0 -107
- package/packages/core/__tests__/subscriber.test.tsx +0 -89
- package/packages/core/__tests__/use-async.test.tsx +0 -45
- package/packages/core/__tests__/use.test.tsx +0 -125
- package/packages/core/create.ts +0 -98
- package/packages/core/subscriber.ts +0 -165
- package/packages/core/types.ts +0 -15
- package/packages/core/use.ts +0 -57
- package/packages/core/utils/__tests__/context.test.ts +0 -198
- package/packages/core/utils/__tests__/sub-memo.test.ts +0 -13
- package/packages/core/utils/create-context.ts +0 -60
- package/packages/core/utils/scheduler.ts +0 -59
- package/packages/core/utils/sub-memo.ts +0 -49
- package/types/subscriber.d.ts +0 -25
- package/types/use.d.ts +0 -2
- package/types/utils/create-context.d.ts +0 -5
- package/types/utils/global-scheduler.d.ts +0 -5
- package/types/utils/sub-memo.d.ts +0 -7
- /package/{packages/core → src}/__tests__/test-utils.ts +0 -0
- /package/{packages/core → src}/utils/__tests__/shallow.test.ts +0 -0
- /package/{packages/core → src}/utils/create-emitter.ts +0 -0
- /package/{packages/core → src}/utils/shallow.ts +0 -0
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { create } from '../create'
|
|
2
|
-
import { waitFor } from '@testing-library/react'
|
|
3
|
-
import { longPromise } from './test-utils'
|
|
4
|
-
import { isPromise } from '../utils/is'
|
|
5
|
-
import { subscriber } from '../subscriber'
|
|
6
|
-
|
|
7
|
-
describe('create', () => {
|
|
8
|
-
it('should subscribe to context and notified it with parameters', async () => {
|
|
9
|
-
const state1 = create(1)
|
|
10
|
-
const state2 = create(2)
|
|
11
|
-
|
|
12
|
-
function derivedNested() {
|
|
13
|
-
return state1() + state2()
|
|
14
|
-
}
|
|
15
|
-
async function derived(plus: number) {
|
|
16
|
-
return state1() + state2() + derivedNested() + plus
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let updatesCounter = 0
|
|
20
|
-
const sub = subscriber(() => derived(10))
|
|
21
|
-
expect(isPromise(sub.emitter.getSnapshot())).toBe(true)
|
|
22
|
-
sub.listen(async () => {
|
|
23
|
-
updatesCounter++
|
|
24
|
-
})
|
|
25
|
-
expect(updatesCounter).toBe(0)
|
|
26
|
-
// check if there is not maximum call stack
|
|
27
|
-
expect(await sub()).toBe(16)
|
|
28
|
-
|
|
29
|
-
state1.set(2)
|
|
30
|
-
//
|
|
31
|
-
await waitFor(async () => {})
|
|
32
|
-
expect(await sub()).toBe(18)
|
|
33
|
-
|
|
34
|
-
expect(updatesCounter).toBe(4)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('should async subscribe to context and notified it', async () => {
|
|
38
|
-
const state1 = create(1)
|
|
39
|
-
const state2 = create(Promise.resolve(2))
|
|
40
|
-
|
|
41
|
-
async function derivedNested() {
|
|
42
|
-
await longPromise()
|
|
43
|
-
return state1() + (await state2())
|
|
44
|
-
}
|
|
45
|
-
async function derived() {
|
|
46
|
-
return state1() + (await state2()) + (await derivedNested())
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
let updatesCounter = 0
|
|
50
|
-
|
|
51
|
-
const sub = subscriber(derived)
|
|
52
|
-
|
|
53
|
-
sub.listen(() => {
|
|
54
|
-
updatesCounter++
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
// check if there is not maximum call stack
|
|
58
|
-
sub()
|
|
59
|
-
|
|
60
|
-
// check if not assigned multiple times, but only once
|
|
61
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
62
|
-
expect(state2.emitter.getSize()).toBe(1)
|
|
63
|
-
expect(sub.emitter.getSize()).toBe(1)
|
|
64
|
-
state1.set(2)
|
|
65
|
-
|
|
66
|
-
await waitFor(async () => {
|
|
67
|
-
expect(await sub()).toBe(8)
|
|
68
|
-
expect(updatesCounter).toBe(5)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
state2.set(3)
|
|
72
|
-
|
|
73
|
-
await waitFor(async () => {
|
|
74
|
-
expect(await sub()).toBe(10)
|
|
75
|
-
expect(updatesCounter).toBe(10)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
79
|
-
expect(state2.emitter.getSize()).toBe(1)
|
|
80
|
-
expect(sub.emitter.getSize()).toBe(1)
|
|
81
|
-
|
|
82
|
-
sub.destroy()
|
|
83
|
-
|
|
84
|
-
expect(state1.emitter.getSize()).toBe(0)
|
|
85
|
-
expect(state2.emitter.getSize()).toBe(0)
|
|
86
|
-
expect(sub.emitter.getSize()).toBe(0)
|
|
87
|
-
})
|
|
88
|
-
})
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { create } from '../create'
|
|
2
|
-
import { waitFor } from '@testing-library/react'
|
|
3
|
-
import { subscriber } from '../subscriber'
|
|
4
|
-
|
|
5
|
-
describe('create', () => {
|
|
6
|
-
it('should get basic value states', async () => {
|
|
7
|
-
const state1 = create(1)
|
|
8
|
-
const state2 = create(2)
|
|
9
|
-
expect(state1()).toBe(1)
|
|
10
|
-
expect(state2()).toBe(2)
|
|
11
|
-
|
|
12
|
-
state1.set(2)
|
|
13
|
-
state2.set(3)
|
|
14
|
-
|
|
15
|
-
await waitFor(() => {
|
|
16
|
-
expect(state1()).toBe(2)
|
|
17
|
-
expect(state2()).toBe(3)
|
|
18
|
-
})
|
|
19
|
-
})
|
|
20
|
-
it('should get basic and derived value', async () => {
|
|
21
|
-
const state1 = create(1)
|
|
22
|
-
const state2 = create(2)
|
|
23
|
-
|
|
24
|
-
function derived1() {
|
|
25
|
-
return state1() + state2()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
expect(state1()).toBe(1)
|
|
29
|
-
expect(state2()).toBe(2)
|
|
30
|
-
expect(derived1()).toBe(3)
|
|
31
|
-
|
|
32
|
-
state1.set(2)
|
|
33
|
-
state2.set(3)
|
|
34
|
-
|
|
35
|
-
await waitFor(() => {
|
|
36
|
-
expect(state1()).toBe(2)
|
|
37
|
-
expect(state2()).toBe(3)
|
|
38
|
-
expect(derived1()).toBe(5)
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
it('should subscribe to context and notified it', async () => {
|
|
42
|
-
const state1 = create(1)
|
|
43
|
-
const state2 = create(2)
|
|
44
|
-
|
|
45
|
-
function derivedNested() {
|
|
46
|
-
return state1() + state2()
|
|
47
|
-
}
|
|
48
|
-
function derived() {
|
|
49
|
-
return state1() + state2() + derivedNested()
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let updatesCounter = 0
|
|
53
|
-
|
|
54
|
-
const sub = subscriber(derived)
|
|
55
|
-
|
|
56
|
-
sub.listen(() => {
|
|
57
|
-
updatesCounter++
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
// check if there is not maximum call stack
|
|
61
|
-
sub()
|
|
62
|
-
sub()
|
|
63
|
-
sub()
|
|
64
|
-
|
|
65
|
-
// check if not assigned multiple times, but only once
|
|
66
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
67
|
-
expect(state2.emitter.getSize()).toBe(1)
|
|
68
|
-
expect(sub.emitter.getSize()).toBe(1)
|
|
69
|
-
expect(sub.emitter.getSnapshot()).toBe(6)
|
|
70
|
-
state1.set(2)
|
|
71
|
-
|
|
72
|
-
await waitFor(() => {
|
|
73
|
-
expect(sub()).toBe(8)
|
|
74
|
-
expect(updatesCounter).toBe(1)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
state2.set(3)
|
|
78
|
-
|
|
79
|
-
await waitFor(() => {
|
|
80
|
-
expect(sub()).toBe(10)
|
|
81
|
-
expect(updatesCounter).toBe(2)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
85
|
-
expect(state2.emitter.getSize()).toBe(1)
|
|
86
|
-
expect(sub.emitter.getSize()).toBe(1)
|
|
87
|
-
expect(sub.emitter.getSnapshot()).toBe(10)
|
|
88
|
-
|
|
89
|
-
sub.destroy()
|
|
90
|
-
|
|
91
|
-
expect(state1.emitter.getSize()).toBe(0)
|
|
92
|
-
expect(state2.emitter.getSize()).toBe(0)
|
|
93
|
-
expect(sub.emitter.getSize()).toBe(0)
|
|
94
|
-
})
|
|
95
|
-
it('should subscribe and set snapshot', async () => {
|
|
96
|
-
const state = create(1)
|
|
97
|
-
const sub = subscriber(state)
|
|
98
|
-
sub()
|
|
99
|
-
|
|
100
|
-
expect(sub.emitter.getSnapshot()).toBe(1)
|
|
101
|
-
|
|
102
|
-
state.set(2)
|
|
103
|
-
await waitFor(() => {
|
|
104
|
-
expect(sub.emitter.getSnapshot()).toBe(2)
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
})
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { waitFor } from '@testing-library/react'
|
|
2
|
-
import { create } from '../create'
|
|
3
|
-
import { subscriber } from '../subscriber'
|
|
4
|
-
import { longPromise } from './test-utils'
|
|
5
|
-
|
|
6
|
-
describe('subscriber', () => {
|
|
7
|
-
it('should test subscriber and cleaning the emitters', () => {
|
|
8
|
-
const state1 = create(1)
|
|
9
|
-
const sub = subscriber(state1)
|
|
10
|
-
// at this point, the emitter is not subscribed yet, as it need to be called first.
|
|
11
|
-
expect(state1.emitter.getSize()).toBe(0)
|
|
12
|
-
|
|
13
|
-
// check if the value is correct
|
|
14
|
-
expect(sub()).toBe(1)
|
|
15
|
-
|
|
16
|
-
// now we can check if the value is subscribed
|
|
17
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
18
|
-
// we destroy the subscriber, meaning that the emitter should be cleaned
|
|
19
|
-
|
|
20
|
-
sub.destroy()
|
|
21
|
-
|
|
22
|
-
expect(state1.emitter.getSize()).toBe(0)
|
|
23
|
-
|
|
24
|
-
// and test re-aligning the subscriber
|
|
25
|
-
expect(sub()).toBe(1)
|
|
26
|
-
expect(state1.emitter.getSize()).toBe(1)
|
|
27
|
-
})
|
|
28
|
-
it('should test how many events are emitter via singleton state', async () => {
|
|
29
|
-
const state1 = create(1)
|
|
30
|
-
const sub = subscriber(state1)
|
|
31
|
-
|
|
32
|
-
let updateCount = 0
|
|
33
|
-
|
|
34
|
-
sub.listen(() => {
|
|
35
|
-
updateCount++
|
|
36
|
-
})
|
|
37
|
-
sub()
|
|
38
|
-
await waitFor(() => {})
|
|
39
|
-
// we do not received initial value as it is not changed
|
|
40
|
-
expect(updateCount).toBe(0)
|
|
41
|
-
|
|
42
|
-
state1.set(2)
|
|
43
|
-
await waitFor(() => {})
|
|
44
|
-
expect(updateCount).toBe(1)
|
|
45
|
-
})
|
|
46
|
-
it('should test how many events are emitter via singleton async state', async () => {
|
|
47
|
-
const state1 = create(longPromise())
|
|
48
|
-
const sub = subscriber(state1)
|
|
49
|
-
|
|
50
|
-
let updateCount = 0
|
|
51
|
-
|
|
52
|
-
sub.listen(() => {
|
|
53
|
-
updateCount++
|
|
54
|
-
})
|
|
55
|
-
sub()
|
|
56
|
-
await waitFor(() => {})
|
|
57
|
-
// we do not received initial value as it is not changed
|
|
58
|
-
expect(updateCount).toBe(0)
|
|
59
|
-
|
|
60
|
-
state1.set(2)
|
|
61
|
-
await waitFor(() => {})
|
|
62
|
-
expect(updateCount).toBe(1)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should test how many events are emitter via derived state', async () => {
|
|
66
|
-
const state1 = create(longPromise())
|
|
67
|
-
|
|
68
|
-
async function derived() {
|
|
69
|
-
// await longPromise()
|
|
70
|
-
return await state1()
|
|
71
|
-
}
|
|
72
|
-
const sub = subscriber(derived)
|
|
73
|
-
|
|
74
|
-
let updateCount = 0
|
|
75
|
-
|
|
76
|
-
sub.listen(() => {
|
|
77
|
-
updateCount++
|
|
78
|
-
})
|
|
79
|
-
await sub()
|
|
80
|
-
await waitFor(() => {})
|
|
81
|
-
expect(await sub()).toBe(0)
|
|
82
|
-
// // we do not received initial value as it is not changed
|
|
83
|
-
expect(updateCount).toBe(2)
|
|
84
|
-
|
|
85
|
-
// state1.set(2)
|
|
86
|
-
// await waitFor(() => {})
|
|
87
|
-
// expect(updateCount).toBe(1)
|
|
88
|
-
})
|
|
89
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
-
import { renderHook } from '@testing-library/react-hooks'
|
|
3
|
-
import { create } from '../create'
|
|
4
|
-
import { use } from '../use'
|
|
5
|
-
import { Suspense } from 'react'
|
|
6
|
-
import { waitFor } from '@testing-library/react'
|
|
7
|
-
|
|
8
|
-
describe('use-create', () => {
|
|
9
|
-
const reRendersBefore = jest.fn()
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
jest.clearAllMocks()
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('should test sub hook', async () => {
|
|
16
|
-
const userState = create({ name: 'John', age: 30 })
|
|
17
|
-
async function getDataWithUser() {
|
|
18
|
-
const result = await fetch('https://jsonplaceholder.typicode.com/todos/1')
|
|
19
|
-
const json = await result.json()
|
|
20
|
-
return { age: userState().age, ...json }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const suspenseFunction = jest.fn()
|
|
24
|
-
function Loading() {
|
|
25
|
-
suspenseFunction()
|
|
26
|
-
return <div>Loading...</div>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const { result } = renderHook(
|
|
30
|
-
() => {
|
|
31
|
-
reRendersBefore()
|
|
32
|
-
const data = use(getDataWithUser)
|
|
33
|
-
return data
|
|
34
|
-
},
|
|
35
|
-
// @ts-expect-error
|
|
36
|
-
{ wrapper: ({ children }) => <Suspense fallback={<Loading />}>{children}</Suspense> },
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
await waitFor(() => {
|
|
40
|
-
expect(result.current).toEqual({ userId: 1, id: 1, title: 'delectus aut autem', completed: false, age: 30 })
|
|
41
|
-
})
|
|
42
|
-
expect(suspenseFunction).toHaveBeenCalledTimes(1)
|
|
43
|
-
expect(result.current).toEqual({ userId: 1, id: 1, title: 'delectus aut autem', completed: false, age: 30 })
|
|
44
|
-
})
|
|
45
|
-
})
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { act, renderHook } from '@testing-library/react-hooks'
|
|
2
|
-
import { create } from '../create'
|
|
3
|
-
import { use } from '../use'
|
|
4
|
-
import { waitFor } from '@testing-library/react'
|
|
5
|
-
import { useCallback } from 'react'
|
|
6
|
-
import { getDebugCacheCreation } from '../utils/sub-memo'
|
|
7
|
-
|
|
8
|
-
describe('use-create', () => {
|
|
9
|
-
const reRendersBefore = jest.fn()
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
jest.clearAllMocks()
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('should test use hook', async () => {
|
|
16
|
-
const state = create(1)
|
|
17
|
-
|
|
18
|
-
const { result } = renderHook(() => {
|
|
19
|
-
reRendersBefore()
|
|
20
|
-
return use(state)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
state.set(2)
|
|
24
|
-
|
|
25
|
-
await waitFor(() => {})
|
|
26
|
-
expect(result.current).toBe(2)
|
|
27
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(2)
|
|
28
|
-
|
|
29
|
-
state.set(3)
|
|
30
|
-
|
|
31
|
-
await waitFor(() => {})
|
|
32
|
-
expect(result.current).toBe(3)
|
|
33
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(3)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should test derived state with multiple states', async () => {
|
|
37
|
-
const state1 = create(1)
|
|
38
|
-
const state2 = create(2)
|
|
39
|
-
|
|
40
|
-
function derivedBefore(plusValue: number) {
|
|
41
|
-
return state1() + state2() + plusValue
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function derived() {
|
|
45
|
-
return state1() + state2() + derivedBefore(10)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const { result } = renderHook(() => {
|
|
49
|
-
reRendersBefore()
|
|
50
|
-
return use(derived)
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
await waitFor(() => {})
|
|
54
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(1)
|
|
55
|
-
act(() => {
|
|
56
|
-
state1.set(2)
|
|
57
|
-
state2.set(3)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
await waitFor(() => {})
|
|
61
|
-
expect(result.current).toBe(20)
|
|
62
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(2)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should test use hook without memoize fn', async () => {
|
|
66
|
-
const state1 = create(1)
|
|
67
|
-
const state2 = create(2)
|
|
68
|
-
|
|
69
|
-
function derivedBefore(plusValue: number) {
|
|
70
|
-
return state1() + state2() + plusValue
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function derived(add: number) {
|
|
74
|
-
return state1() + state2() + derivedBefore(add)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const { result } = renderHook(() => {
|
|
78
|
-
reRendersBefore()
|
|
79
|
-
return use(() => derived(10))
|
|
80
|
-
})
|
|
81
|
-
expect(getDebugCacheCreation()).toBe(1)
|
|
82
|
-
|
|
83
|
-
await waitFor(() => {})
|
|
84
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(1)
|
|
85
|
-
act(() => {
|
|
86
|
-
state1.set(2)
|
|
87
|
-
state2.set(3)
|
|
88
|
-
})
|
|
89
|
-
expect(getDebugCacheCreation()).toBe(1)
|
|
90
|
-
await waitFor(() => {})
|
|
91
|
-
expect(result.current).toBe(20)
|
|
92
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(2)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('should test use hook with memoize fn', async () => {
|
|
96
|
-
const state1 = create(1)
|
|
97
|
-
const state2 = create(2)
|
|
98
|
-
|
|
99
|
-
function derivedBefore(plusValue: number) {
|
|
100
|
-
return state1() + state2() + plusValue
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function derived(add: number) {
|
|
104
|
-
return state1() + state2() + derivedBefore(add)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const { result } = renderHook(() => {
|
|
108
|
-
reRendersBefore()
|
|
109
|
-
const memoized = useCallback(() => derived(10), [])
|
|
110
|
-
return use(memoized)
|
|
111
|
-
})
|
|
112
|
-
expect(getDebugCacheCreation()).toBe(1)
|
|
113
|
-
|
|
114
|
-
await waitFor(() => {})
|
|
115
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(1)
|
|
116
|
-
act(() => {
|
|
117
|
-
state1.set(2)
|
|
118
|
-
state2.set(3)
|
|
119
|
-
})
|
|
120
|
-
expect(getDebugCacheCreation()).toBe(1)
|
|
121
|
-
await waitFor(() => {})
|
|
122
|
-
expect(result.current).toBe(20)
|
|
123
|
-
expect(reRendersBefore).toHaveBeenCalledTimes(2)
|
|
124
|
-
})
|
|
125
|
-
})
|
package/packages/core/create.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { canUpdate, generateId } from './utils/common'
|
|
2
|
-
import type { Emitter } from './utils/create-emitter'
|
|
3
|
-
import { createEmitter } from './utils/create-emitter'
|
|
4
|
-
import { isEqualBase, isFunction, isSetValueFunction, isUndefined } from './utils/is'
|
|
5
|
-
// import { createScheduler } from './utils/scheduler'
|
|
6
|
-
import type { Cache, Callable, DefaultValue, IsEqual, Listener, SetValue } from './types'
|
|
7
|
-
import { context } from './subscriber'
|
|
8
|
-
import { createGlobalScheduler } from './utils/global-scheduler'
|
|
9
|
-
|
|
10
|
-
export const createScheduler = createGlobalScheduler()
|
|
11
|
-
interface RawState<T> {
|
|
12
|
-
(): T
|
|
13
|
-
id: number
|
|
14
|
-
set: (value: SetValue<T>) => void
|
|
15
|
-
emitter: Emitter<T>
|
|
16
|
-
listen: Listener<T>
|
|
17
|
-
destroy: () => void
|
|
18
|
-
withName: (name: string) => RawState<T>
|
|
19
|
-
stateName?: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type State<T> = {
|
|
23
|
-
readonly [K in keyof RawState<T>]: RawState<T>[K]
|
|
24
|
-
} & Callable<T>
|
|
25
|
-
|
|
26
|
-
export function create<T>(initialValue: DefaultValue<T>, isEqual: IsEqual<T> = isEqualBase): State<T> {
|
|
27
|
-
const cache: Cache<T> = {}
|
|
28
|
-
|
|
29
|
-
function getValue(): T {
|
|
30
|
-
if (isUndefined(cache.current)) {
|
|
31
|
-
cache.current = isFunction(initialValue) ? initialValue() : initialValue
|
|
32
|
-
}
|
|
33
|
-
return cache.current
|
|
34
|
-
}
|
|
35
|
-
function resolveValue(value: SetValue<T>) {
|
|
36
|
-
const previous = getValue()
|
|
37
|
-
cache.current = isSetValueFunction(value) ? value(previous) : value
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// const schedule = createScheduler<SetValue<T>>({
|
|
41
|
-
// onFinish() {
|
|
42
|
-
// cache.current = getValue()
|
|
43
|
-
// if (!canUpdate(cache, isEqual)) {
|
|
44
|
-
// return
|
|
45
|
-
// }
|
|
46
|
-
// state.emitter.emit()
|
|
47
|
-
// },
|
|
48
|
-
// onResolveItem: resolveValue,
|
|
49
|
-
// })
|
|
50
|
-
|
|
51
|
-
const state: RawState<T> = function () {
|
|
52
|
-
const stateValue = getValue()
|
|
53
|
-
const ctx = context.use()
|
|
54
|
-
// console.log('CTX', ctx?.id, 'STATE', state.id)
|
|
55
|
-
if (ctx && !state.emitter.contains(ctx.sub)) {
|
|
56
|
-
ctx.addEmitter(state.emitter)
|
|
57
|
-
}
|
|
58
|
-
return stateValue
|
|
59
|
-
}
|
|
60
|
-
state.listen = function (listener: (value: T) => void) {
|
|
61
|
-
return state.emitter.subscribe(() => {
|
|
62
|
-
const final = cache.current
|
|
63
|
-
if (isUndefined(final)) {
|
|
64
|
-
throw new Error('The value is undefined')
|
|
65
|
-
}
|
|
66
|
-
listener(final)
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
state.emitter = createEmitter<T>(() => state())
|
|
70
|
-
state.id = generateId()
|
|
71
|
-
|
|
72
|
-
const clearScheduler = createScheduler.add(state.id, {
|
|
73
|
-
onFinish() {
|
|
74
|
-
cache.current = getValue()
|
|
75
|
-
if (!canUpdate(cache, isEqual)) {
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
state.emitter.emit()
|
|
79
|
-
},
|
|
80
|
-
onResolveItem: resolveValue,
|
|
81
|
-
})
|
|
82
|
-
state.set = function (value) {
|
|
83
|
-
createScheduler.schedule(state.id, value)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
state.destroy = function () {
|
|
87
|
-
cache.current = undefined
|
|
88
|
-
getValue()
|
|
89
|
-
clearScheduler()
|
|
90
|
-
state.emitter.clear()
|
|
91
|
-
}
|
|
92
|
-
state.withName = function (name: string) {
|
|
93
|
-
state.stateName = name
|
|
94
|
-
return state
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return state
|
|
98
|
-
}
|