Skip to content

Commit

Permalink
fix(core): skipCount should less equal than the filtered index
Browse files Browse the repository at this point in the history
  • Loading branch information
LongYinan committed Aug 24, 2021
1 parent 0499b48 commit ff38eb6
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 3 deletions.
56 changes: 55 additions & 1 deletion packages/core/src/__tests__/smoking.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable sonarjs/no-identical-functions */

import 'reflect-metadata'
import { rootInjector } from '@sigi/di'
import { Observable } from 'rxjs'
import { delay, map } from 'rxjs/operators'
import { delay, map, tap } from 'rxjs/operators'
import * as Sinon from 'sinon'

import { Reducer, Effect } from '../decorators'
Expand Down Expand Up @@ -83,4 +85,56 @@ describe('Smoking tests', () => {
timer.restore()
rootInjector.reset()
})

it('should skip all effects restored from persisted state', () => {
type State = { foo: string; bar: number }
const staticState = { foo: 'foo', bar: 42 }
global['SIGI_STATE'] = {
SSRPersistModule: staticState,
}
const spy = Sinon.spy()
@Module('SSRPersistModule')
class SSRPersistModule extends EffectModule<State> {
defaultState = {
foo: '1',
bar: 2,
}

@Reducer()
set(state: State, payload: string | number) {
if (typeof payload === 'string') {
return { ...state, foo: payload }
} else {
return { ...state, bar: payload }
}
}

@Effect({
payloadGetter: () => '2',
})
setFoo(payload$: Observable<string>) {
return payload$.pipe(
tap(spy),
map((payload) => this.getActions().set(payload)),
)
}

@Effect({
payloadGetter: () => 3,
})
setBar(payload$: Observable<number>) {
return payload$.pipe(
tap(spy),
map((payload) => this.getActions().set(payload)),
)
}
}

const module = rootInjector.getInstance(SSRPersistModule)
module.dispatchers.setFoo(staticState.foo + 1)
module.dispatchers.setBar(staticState.bar + 1)
expect(spy.callCount).toBe(0)
expect(module.state.foo).toBe(staticState.foo)
expect(module.state.bar).toBe(staticState.bar)
})
})
9 changes: 7 additions & 2 deletions packages/core/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,14 @@ export abstract class EffectModule<S> {
...effectKeys.map((name) => {
const effect: Effect<unknown> = (this as any)[name]
const payload$ = action$.pipe(
filter(({ type }, index) => {
filter(({ type }) => type === name),
// If this Module restored from `SIGI_STATE` successfully.
// We should skip the effects decorated by `payloadGetter`, which was dispatched in the server side.
// So we need `filter` the decorated effects by `index: 0`, which is the first time we dispatch the action in the client side.
// Which means we should filter by the `action.type` first, and `filter` by the `index` again then.
filter((_, index) => {
const skipCount = !this.actionsToRetry.has(name) && this.actionsToSkip?.has(name) ? 1 : 0
return type === name && skipCount <= index
return skipCount <= index
}),
map(({ payload }) => payload),
)
Expand Down

0 comments on commit ff38eb6

Please sign in to comment.