Skip to content

Commit 1349288

Browse files
committed
fix(react): should still not skip first setState if not first rendering
1 parent e8fa8fd commit 1349288

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

packages/react/src/__tests__/react.spec.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ describe('Hooks', () => {
146146
expect(testWrapper.root.findByType('div').children[0]).toBe('0')
147147
})
148148

149-
it.only('should not re-render if return state shallow equaled', () => {
149+
it('should not re-render if return state shallow equaled', () => {
150150
const fooSpy = Sinon.spy()
151151
const FooComponent = () => {
152152
const state = useModuleState(CountModel, {
@@ -196,4 +196,41 @@ describe('Hooks', () => {
196196
expect(spy.callCount).toBe(2)
197197
fooSpy.resetHistory()
198198
})
199+
200+
it('should run selector with new closure', () => {
201+
const setPlusCountStub = Sinon.stub()
202+
const FooComponent = () => {
203+
const [plusCount, setPlusCount] = useState(1)
204+
const plusOneCount = useModuleState(CountModel, {
205+
selector: (state) => plusCount + state.count,
206+
dependencies: [plusCount],
207+
})
208+
209+
useEffect(() => {
210+
setPlusCountStub.callsFake(() => {
211+
setPlusCount(2)
212+
})
213+
}, [])
214+
215+
return <div>{plusOneCount}</div>
216+
}
217+
218+
let fooWrapper!: ReactTestRenderer
219+
act(() => {
220+
fooWrapper = create(<FooComponent />)
221+
})
222+
223+
expect(fooWrapper.root.findByType('div').children[0]).toBe('1')
224+
act(() => {
225+
setPlusCountStub()
226+
})
227+
expect(fooWrapper.root.findByType('div').children[0]).toBe('2')
228+
229+
act(() => {
230+
setCountStub()
231+
})
232+
expect(fooWrapper.root.findByType('div').children[0]).toBe('12')
233+
234+
setPlusCountStub.reset()
235+
})
199236
})

packages/react/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { EffectModule, ActionOfEffectModule } from '@sigi/core'
22
import { ConstructorOf, IStore } from '@sigi/types'
3-
import { useMemo, useEffect, useState } from 'react'
3+
import { useMemo, useEffect, useState, useRef } from 'react'
44
import { distinctUntilChanged, map, skip } from 'rxjs/operators'
55

66
import { useInstance } from './injectable-context'
@@ -46,6 +46,7 @@ function _useModuleState<S, U = S>(
4646
}
4747
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
4848
dependencies = dependencies || []
49+
const isFirstRendering = useRef(true)
4950
const [appState, setState] = useState(() => {
5051
const initialState = store.state
5152
return selector ? selector(initialState) : initialState
@@ -57,9 +58,10 @@ function _useModuleState<S, U = S>(
5758
map((s) => (selector ? selector(s) : s)),
5859
distinctUntilChanged((s1, s2) => equalFn(s1, s2)),
5960
// skip initial state emission
60-
skip(1),
61+
skip(isFirstRendering.current ? 1 : 0),
6162
)
6263
.subscribe(setState)
64+
isFirstRendering.current = false
6365
return () => {
6466
subscription.unsubscribe()
6567
}

0 commit comments

Comments
 (0)