Skip to content

Commit c8c31b8

Browse files
committed
add controller to params, edit test
1 parent 0e0022a commit c8c31b8

File tree

7 files changed

+94
-46
lines changed

7 files changed

+94
-46
lines changed

src/Builder/index.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,37 @@ import { Constructor, InferStateType, ShouldUpdate, StateCompare } from '../type
44
import { useControllerResolver } from '../hooks/useControllerResolver'
55
import { useBuilder } from '../hooks/useBuilder'
66

7+
interface BuilderControllerProps<C extends Controller<InferStateType<C>>> {
8+
source: C
9+
buildWhen?: ShouldUpdate<InferStateType<C>>
10+
stateCompare?: StateCompare<InferStateType<C>>
11+
children?: (state: InferStateType<C>) => ReactNode
12+
}
13+
interface BuilderCtorProps<C extends Controller<InferStateType<C>>> {
14+
source: Constructor<C>
15+
buildWhen?: ShouldUpdate<InferStateType<C>>
16+
stateCompare?: StateCompare<InferStateType<C>>
17+
children?: (state: InferStateType<C>, controller: C) => ReactNode
18+
}
19+
720
interface BuilderProps<C extends Controller<InferStateType<C>>> {
821
source: Constructor<C> | C
922
buildWhen?: ShouldUpdate<InferStateType<C>>
1023
stateCompare?: StateCompare<InferStateType<C>>
11-
children: (state: InferStateType<C>) => ReactNode
24+
children?: (state: InferStateType<C>, controller?: C) => ReactNode
1225
}
1326

27+
function Builder<C extends Controller<InferStateType<C>>>(props: BuilderCtorProps<C>): ReactNode | undefined
28+
function Builder<C extends Controller<InferStateType<C>>>(props: BuilderControllerProps<C>): ReactNode | undefined
1429
function Builder<C extends Controller<InferStateType<C>>>({
1530
source,
1631
buildWhen,
1732
stateCompare,
1833
children,
19-
}: BuilderProps<C>) {
34+
}: BuilderProps<C>): ReactNode | undefined {
2035
const controller = useControllerResolver(source)
2136
const state = useBuilder(controller, buildWhen, stateCompare)
22-
return children(state)
37+
return children?.(state, controller)
2338
}
2439

25-
export { Builder, BuilderProps }
40+
export { Builder, BuilderProps, BuilderControllerProps, BuilderCtorProps }

src/Listener/index.tsx

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
1-
import { ReactNode } from 'react'
1+
import { ReactNode, useCallback } from 'react'
22
import Controller from '../Controller'
33
import { Constructor, InferStateType, ShouldUpdate, StateCompare } from '../types'
44
import { useListener } from '../hooks/useListener'
55
import { useControllerResolver } from '../hooks/useControllerResolver'
66

7+
interface ListenerControllerProps<C extends Controller<InferStateType<C>>> {
8+
source: C
9+
listener: (state: InferStateType<C>) => void
10+
listenWhen?: ShouldUpdate<InferStateType<C>>
11+
stateCompare?: StateCompare<InferStateType<C>>
12+
children?: ReactNode
13+
}
14+
interface ListenerCtorProps<C extends Controller<InferStateType<C>>> {
15+
source: Constructor<C>
16+
listener: (state: InferStateType<C>, controller: C) => void
17+
listenWhen?: ShouldUpdate<InferStateType<C>>
18+
stateCompare?: StateCompare<InferStateType<C>>
19+
children?: ReactNode
20+
}
21+
722
interface ListenerProps<C extends Controller<InferStateType<C>>> {
823
source: Constructor<C> | C
9-
listener: (state: InferStateType<C>) => void
24+
listener: (state: InferStateType<C>, controller?: C) => void
1025
listenWhen?: ShouldUpdate<InferStateType<C>>
1126
stateCompare?: StateCompare<InferStateType<C>>
1227
children?: ReactNode
1328
}
1429

30+
function Listener<C extends Controller<InferStateType<C>>>(props: ListenerCtorProps<C>): ReactNode | undefined
31+
function Listener<C extends Controller<InferStateType<C>>>(props: ListenerControllerProps<C>): ReactNode | undefined
1532
function Listener<C extends Controller<InferStateType<C>>>({
1633
source,
1734
listener,
1835
listenWhen,
1936
stateCompare,
2037
children,
21-
}: ListenerProps<C>) {
38+
}: ListenerProps<C>): ReactNode | undefined {
2239
const controller = useControllerResolver(source)
23-
useListener(controller, listener, listenWhen, stateCompare)
40+
const listenerCallback = useCallback(
41+
(state: InferStateType<C>) => {
42+
listener(state, controller)
43+
},
44+
[listener, controller],
45+
)
46+
useListener(controller, listenerCallback, listenWhen, stateCompare)
2447
return children
2548
}
2649

27-
export { Listener, ListenerProps }
50+
export { Listener, ListenerProps, ListenerControllerProps, ListenerCtorProps }

src/Selector/index.tsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,39 @@ import { Constructor, InferStateType, StateCompare } from '../types'
44
import { useControllerResolver } from '../hooks/useControllerResolver'
55
import { useSelector } from '../hooks/useSelector'
66

7+
interface SelectorControllerProps<C extends Controller<InferStateType<C>>, T> {
8+
source: C
9+
selector: (state: InferStateType<C>) => T
10+
stateCompare?: StateCompare<T>
11+
children?: (value: T) => ReactNode
12+
}
13+
interface SelectorCtorProps<C extends Controller<InferStateType<C>>, T> {
14+
source: Constructor<C>
15+
selector: (state: InferStateType<C>) => T
16+
stateCompare?: StateCompare<T>
17+
children?: (value: T, controller: C) => ReactNode
18+
}
19+
720
interface SelectorProps<C extends Controller<InferStateType<C>>, T> {
821
source: Constructor<C> | C
922
selector: (state: InferStateType<C>) => T
1023
stateCompare?: StateCompare<T>
11-
children: (value: T) => ReactNode
24+
children?: (value: T, controller?: C) => ReactNode
1225
}
1326

27+
function Selector<C extends Controller<InferStateType<C>>, T>(
28+
props: SelectorControllerProps<C, T>,
29+
): ReactNode | undefined
30+
function Selector<C extends Controller<InferStateType<C>>, T>(props: SelectorCtorProps<C, T>): ReactNode | undefined
1431
function Selector<C extends Controller<InferStateType<C>>, T>({
1532
source,
1633
selector,
1734
stateCompare,
1835
children,
19-
}: SelectorProps<C, T>) {
36+
}: SelectorProps<C, T>): ReactNode | undefined {
2037
const controller = useControllerResolver(source)
2138
const value = useSelector(controller, selector, stateCompare)
22-
return children(value)
39+
return children?.(value, controller)
2340
}
2441

25-
export { Selector, SelectorProps }
42+
export { Selector, SelectorProps, SelectorControllerProps, SelectorCtorProps }

src/hooks/useListener.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { isEqual } from '../utils'
66

77
function useListener<C extends Controller<InferStateType<C>>>(
88
ctor: Constructor<C>,
9-
listener: (state: InferStateType<C>) => void,
9+
listener: (state: InferStateType<C>, controller: C) => void,
1010
listenWhen?: ShouldUpdate<InferStateType<C>>,
1111
stateCompare?: StateCompare<InferStateType<C>>,
1212
): C
@@ -20,7 +20,7 @@ function useListener<C extends Controller<InferStateType<C>>>(
2020

2121
function useListener<C extends Controller<InferStateType<C>>>(
2222
source: Constructor<C> | C,
23-
listener: (state: InferStateType<C>) => void,
23+
listener: (state: InferStateType<C>, controller?: C) => void,
2424
listenWhen?: ShouldUpdate<InferStateType<C>>,
2525
stateCompare?: StateCompare<InferStateType<C>>,
2626
): C | undefined {
@@ -59,10 +59,10 @@ function useListener<C extends Controller<InferStateType<C>>>(
5959
}
6060
if (listenWhenRef.current !== undefined) {
6161
if (listenWhenRef.current(currentState, state)) {
62-
listenerRef.current(state)
62+
listenerRef.current(state, controller)
6363
}
6464
} else {
65-
listenerRef.current(state)
65+
listenerRef.current(state, controller)
6666
}
6767
stateRef.current = state
6868
})

src/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import { useListener } from './hooks/useListener'
1414
import { useBuilder } from './hooks/useBuilder'
1515
import { useSelector } from './hooks/useSelector'
1616
import { useControllerResolver } from './hooks/useControllerResolver'
17-
import { Listener, ListenerProps } from './Listener'
18-
import { Builder, BuilderProps } from './Builder'
19-
import { Selector, SelectorProps } from './Selector'
17+
import { Listener, ListenerProps, ListenerControllerProps, ListenerCtorProps } from './Listener'
18+
import { Builder, BuilderProps, BuilderControllerProps, BuilderCtorProps } from './Builder'
19+
import { Selector, SelectorProps, SelectorControllerProps, SelectorCtorProps } from './Selector'
2020
import { isEqual } from './utils'
2121

2222
export { isEqual }
23-
export { Selector, SelectorProps }
24-
export { Builder, BuilderProps }
25-
export { Listener, ListenerProps }
23+
export { Selector, SelectorProps, SelectorControllerProps, SelectorCtorProps }
24+
export { Builder, BuilderProps, BuilderControllerProps, BuilderCtorProps }
25+
export { Listener, ListenerProps, ListenerControllerProps, ListenerCtorProps }
2626
export { useSelector }
2727
export { useBuilder }
2828
export { useListener }

tests/Listener/listener_ctor.test.tsx

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ it('emit object values every reEmit', () => {
4040
})
4141

4242
type DisplayRenderedProps = {
43-
callback: (state: number) => void
43+
callback: (state: number, controller: TestController) => void
4444
listenWhen?: (prev: number, curr: number) => boolean
4545
stateComp?: (prev: number, curr: number) => boolean
4646
}
@@ -52,7 +52,7 @@ const DisplayRendered = ({ callback, listenWhen, stateComp }: DisplayRenderedPro
5252
)
5353
}
5454
it('listenWhen respected', (done) => {
55-
const callbackFn = jest.fn((state) => state)
55+
const callbackFn = jest.fn((state: number, controller: TestController) => [state, controller])
5656
const listenWhenFn = jest.fn((prev, curr) => prev === curr)
5757
const instance = new TestController()
5858
const { container } = render(
@@ -85,7 +85,7 @@ it('listenWhen respected', (done) => {
8585
})
8686

8787
it('listener called', (done) => {
88-
const callbackFn = jest.fn((x: number) => x)
88+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
8989
const instance = new TestController()
9090
const { container } = render(
9191
<ControllerProvider ctor={TestController} source={instance}>
@@ -102,6 +102,7 @@ it('listener called', (done) => {
102102
instance.inc()
103103
instance.inc()
104104
expect(callbackFn).toHaveBeenCalledTimes(5)
105+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
105106
expect(callbackFn.mock.calls[0][0]).toBe(1)
106107
expect(callbackFn.mock.calls[1][0]).toBe(2)
107108
expect(callbackFn.mock.calls[2][0]).toBe(3)
@@ -111,7 +112,7 @@ it('listener called', (done) => {
111112
})
112113

113114
it('default state compare respected', (done) => {
114-
const callbackFn = jest.fn((x: number) => x)
115+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
115116
const instance = new TestController()
116117
const { container } = render(
117118
<ControllerProvider ctor={TestController} source={instance}>
@@ -129,12 +130,13 @@ it('default state compare respected', (done) => {
129130
instance.reEmit()
130131
instance.reEmit()
131132
expect(callbackFn).toHaveBeenCalledTimes(1)
133+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
132134
expect(callbackFn.mock.calls[0][0]).toBe(1)
133135
done()
134136
})
135137

136138
it('specified state compare respected', (done) => {
137-
const callbackFn = jest.fn((x: number) => x)
139+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
138140
const instance = new TestController()
139141
const { container } = render(
140142
<ControllerProvider ctor={TestController} source={instance}>
@@ -152,6 +154,7 @@ it('specified state compare respected', (done) => {
152154
instance.reEmit()
153155
instance.reEmit()
154156
expect(callbackFn).toHaveBeenCalledTimes(6)
157+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
155158
expect(callbackFn.mock.calls[0][0]).toBe(1)
156159
expect(callbackFn.mock.calls[0][0]).toBe(1)
157160
expect(callbackFn.mock.calls[1][0]).toBe(1)
@@ -169,19 +172,6 @@ const DisplayRenderedProvided = () => {
169172
)
170173
}
171174

172-
it('ctor useListener return controller', () => {
173-
const instance = new TestController(5)
174-
const { container } = render(
175-
<ControllerProvider ctor={TestController} source={instance}>
176-
<DisplayRenderedProvided />
177-
</ControllerProvider>,
178-
)
179-
const rendered = getByTestId(container, 'text')
180-
const renderedText = rendered.textContent
181-
const expectedText = 'Rendered'
182-
expect(renderedText).toBe(expectedText)
183-
})
184-
185175
it('throw error when not provided ctor', async () => {
186176
jest.spyOn(console, 'error').mockImplementation(() => jest.fn())
187177

tests/hooks/use_listener/use_listener_ctor.test.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ it('emit object values every reEmit', () => {
4040
})
4141

4242
type DisplayRenderedProps = {
43-
callback: (state: number) => void
43+
callback: (state: number, controller: TestController) => void
4444
listenWhen?: (prev: number, curr: number) => boolean
4545
stateComp?: (prev: number, curr: number) => boolean
4646
}
@@ -50,7 +50,7 @@ const DisplayRendered = ({ callback, listenWhen, stateComp }: DisplayRenderedPro
5050
}
5151

5252
it('listenWhen respected', (done) => {
53-
const callbackFn = jest.fn((state) => state)
53+
const callbackFn = jest.fn((state: number, controller: TestController) => [state, controller])
5454
const listenWhenFn = jest.fn((prev, curr) => prev === curr)
5555
const instance = new TestController()
5656
const { container } = render(
@@ -83,7 +83,7 @@ it('listenWhen respected', (done) => {
8383
})
8484

8585
it('listener called', (done) => {
86-
const callbackFn = jest.fn((x: number) => x)
86+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
8787
const instance = new TestController()
8888
const { container } = render(
8989
<ControllerProvider ctor={TestController} source={instance}>
@@ -100,6 +100,7 @@ it('listener called', (done) => {
100100
instance.inc()
101101
instance.inc()
102102
expect(callbackFn).toHaveBeenCalledTimes(5)
103+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
103104
expect(callbackFn.mock.calls[0][0]).toBe(1)
104105
expect(callbackFn.mock.calls[1][0]).toBe(2)
105106
expect(callbackFn.mock.calls[2][0]).toBe(3)
@@ -109,7 +110,7 @@ it('listener called', (done) => {
109110
})
110111

111112
it('default state compare respected', (done) => {
112-
const callbackFn = jest.fn((x: number) => x)
113+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
113114
const instance = new TestController()
114115
const { container } = render(
115116
<ControllerProvider ctor={TestController} source={instance}>
@@ -127,12 +128,13 @@ it('default state compare respected', (done) => {
127128
instance.reEmit()
128129
instance.reEmit()
129130
expect(callbackFn).toHaveBeenCalledTimes(1)
131+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
130132
expect(callbackFn.mock.calls[0][0]).toBe(1)
131133
done()
132134
})
133135

134136
it('specified state compare respected', (done) => {
135-
const callbackFn = jest.fn((x: number) => x)
137+
const callbackFn = jest.fn((x: number, controller: TestController) => [x, controller])
136138
const instance = new TestController()
137139
const { container } = render(
138140
<ControllerProvider ctor={TestController} source={instance}>
@@ -150,6 +152,7 @@ it('specified state compare respected', (done) => {
150152
instance.reEmit()
151153
instance.reEmit()
152154
expect(callbackFn).toHaveBeenCalledTimes(6)
155+
expect(callbackFn.mock.calls[0][1]).toBe(instance)
153156
expect(callbackFn.mock.calls[0][0]).toBe(1)
154157
expect(callbackFn.mock.calls[0][0]).toBe(1)
155158
expect(callbackFn.mock.calls[1][0]).toBe(1)

0 commit comments

Comments
 (0)