Skip to content

Commit bbf7a4f

Browse files
committed
WIP initial todos test
1 parent e757128 commit bbf7a4f

File tree

4 files changed

+149
-25
lines changed

4 files changed

+149
-25
lines changed

Diff for: src/hooks/useSelector.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export function createSelectorHook(context = ReactReduxContext): UseSelector {
170170
// console.log('wrappedOnStoreChange')
171171
return onStoreChange()
172172
}
173-
// console.log('Subscribing to store with tracking')
173+
console.log('Subscribing to store with tracking')
174174
return subscription.addNestedSub(wrappedOnStoreChange, {
175175
trigger: 'tracked',
176176
cache: cacheWrapper.current,

Diff for: src/utils/Subscription.ts

+16-16
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,25 @@ function createListenerCollection() {
3939
},
4040

4141
notify() {
42-
//console.log('Notifying subscribers')
42+
console.log('Notifying subscribers')
4343
batch(() => {
4444
let listener = first
4545
while (listener) {
46-
//console.log('Listener: ', listener)
46+
console.log('Listener: ', listener)
4747
if (listener.trigger == 'tracked') {
4848
if (listener.selectorCache!.cache.needsRecalculation()) {
49-
//console.log('Calling subscriber due to recalc need')
50-
// console.log(
51-
// 'Calling subscriber due to recalc. Revision before: ',
52-
// $REVISION
53-
// )
49+
console.log('Calling subscriber due to recalc need')
50+
console.log(
51+
'Calling subscriber due to recalc. Revision before: ',
52+
$REVISION
53+
)
5454
listener.callback()
55-
//console.log('Revision after: ', $REVISION)
55+
console.log('Revision after: ', $REVISION)
5656
} else {
57-
// console.log(
58-
// 'Skipping subscriber, no recalc: ',
59-
// listener.selectorCache
60-
// )
57+
console.log(
58+
'Skipping subscriber, no recalc: ',
59+
listener.selectorCache
60+
)
6161
}
6262
} else {
6363
listener.callback()
@@ -83,7 +83,7 @@ function createListenerCollection() {
8383
) {
8484
let isSubscribed = true
8585

86-
//console.log('Adding listener: ', options.trigger)
86+
console.log('Adding listener: ', options.trigger)
8787

8888
let listener: Listener = (last = {
8989
callback,
@@ -162,14 +162,14 @@ export function createSubscription(
162162
listener: () => void,
163163
options: AddNestedSubOptions = { trigger: 'always' }
164164
) {
165-
//console.log('addNestedSub: ', options)
165+
console.log('addNestedSub: ', options)
166166
trySubscribe(options)
167167
return listeners.subscribe(listener, options)
168168
}
169169

170170
function notifyNestedSubs() {
171171
if (store && trackingNode) {
172-
//console.log('Updating node in notifyNestedSubs')
172+
console.log('Updating node in notifyNestedSubs')
173173
updateNode(trackingNode, store.getState())
174174
}
175175
listeners.notify()
@@ -187,7 +187,7 @@ export function createSubscription(
187187

188188
function trySubscribe(options: AddNestedSubOptions = { trigger: 'always' }) {
189189
if (!unsubscribe) {
190-
//console.log('trySubscribe, parentSub: ', parentSub)
190+
console.log('trySubscribe, parentSub: ', parentSub)
191191
unsubscribe = parentSub
192192
? parentSub.addNestedSub(handleChangeWrapper, options)
193193
: store.subscribe(handleChangeWrapper)

Diff for: src/utils/autotracking/autotracking.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,15 @@ export class TrackingCache {
8787

8888
needsRecalculation() {
8989
if (!this._needsRecalculation) {
90-
this._needsRecalculation = this.revision > this._cachedRevision
90+
this._needsRecalculation =
91+
this.revision > this._cachedRevision || this._cachedRevision === -1
9192
}
92-
// console.log(
93-
// 'Needs recalculation: ',
94-
// this._needsRecalculation,
95-
// this._cachedRevision,
96-
// this._cachedValue
97-
// )
93+
console.log(
94+
'Needs recalculation: ',
95+
this._needsRecalculation,
96+
this._cachedRevision,
97+
this._cachedValue
98+
)
9899
return this._needsRecalculation
99100
}
100101

Diff for: test/hooks/useSelector.spec.tsx

+124-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import type {
2626
} from '../../src/index'
2727
import type { FunctionComponent, DispatchWithoutAction, ReactNode } from 'react'
2828
import type { Store, AnyAction, Action } from 'redux'
29-
import { createSlice, configureStore } from '@reduxjs/toolkit'
29+
import { createSlice, configureStore, PayloadAction } from '@reduxjs/toolkit'
3030
import type { UseSelectorOptions } from '../../src/hooks/useSelector'
3131

3232
// disable checks by default
@@ -1051,6 +1051,129 @@ describe('React', () => {
10511051
})
10521052
})
10531053
})
1054+
1055+
describe('Auto-tracking behavior checks', () => {
1056+
interface Todo {
1057+
id: number
1058+
name: string
1059+
completed: boolean
1060+
}
1061+
1062+
type TodosState = Todo[]
1063+
1064+
const counterSlice = createSlice({
1065+
name: 'counters',
1066+
initialState: {
1067+
deeply: {
1068+
nested: {
1069+
really: {
1070+
deeply: {
1071+
nested: {
1072+
c1: { value: 0 },
1073+
},
1074+
},
1075+
},
1076+
},
1077+
},
1078+
1079+
c2: { value: 0 },
1080+
},
1081+
reducers: {
1082+
increment1(state) {
1083+
// state.c1.value++
1084+
state.deeply.nested.really.deeply.nested.c1.value++
1085+
},
1086+
increment2(state) {
1087+
state.c2.value++
1088+
},
1089+
},
1090+
})
1091+
1092+
const todosSlice = createSlice({
1093+
name: 'todos',
1094+
initialState: [
1095+
{ id: 0, name: 'a', completed: false },
1096+
{ id: 1, name: 'b', completed: false },
1097+
{ id: 2, name: 'c', completed: false },
1098+
] as TodosState,
1099+
reducers: {
1100+
toggleCompleted(state, action: PayloadAction<number>) {
1101+
const todo = state.find((todo) => todo.id === action.payload)
1102+
if (todo) {
1103+
todo.completed = !todo.completed
1104+
}
1105+
},
1106+
setName(state) {
1107+
state[1].name = 'd'
1108+
},
1109+
},
1110+
})
1111+
1112+
function makeStore() {
1113+
return configureStore({
1114+
reducer: {
1115+
counter: counterSlice.reducer,
1116+
todos: todosSlice.reducer,
1117+
},
1118+
middleware: (gDM) =>
1119+
gDM({
1120+
serializableCheck: false,
1121+
immutableCheck: false,
1122+
}),
1123+
})
1124+
}
1125+
1126+
type AppStore = ReturnType<typeof makeStore>
1127+
let store: AppStore
1128+
type RootState = ReturnType<AppStore['getState']>
1129+
1130+
const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
1131+
1132+
beforeEach(() => {
1133+
store = makeStore()
1134+
})
1135+
1136+
test.only('should correctly handle updates to nested data', async () => {
1137+
let itemSelectorCallsCount = 0
1138+
let listSelectorCallsCount = 0
1139+
function TodoListItem({ todoId }: { todoId: number }) {
1140+
console.log('TodoListItem render: ', todoId)
1141+
const todo = useAppSelector((state) => {
1142+
itemSelectorCallsCount++
1143+
return state.todos.find((t) => t.id === todoId)
1144+
})!
1145+
return (
1146+
<div>
1147+
{todo.id}: {todo.name} ({todo.completed})
1148+
</div>
1149+
)
1150+
}
1151+
1152+
function TodoList() {
1153+
const todoIds = useAppSelector((state) => {
1154+
listSelectorCallsCount++
1155+
return state.todos.map((t) => t.id)
1156+
})
1157+
console.log('TodoList render: ', todoIds)
1158+
return (
1159+
<>
1160+
{todoIds.map((id) => (
1161+
<TodoListItem todoId={id} key={id} />
1162+
))}
1163+
</>
1164+
)
1165+
}
1166+
1167+
rtl.render(
1168+
<Provider store={store} stabilityCheck="never">
1169+
<TodoList />
1170+
</Provider>
1171+
)
1172+
1173+
expect(listSelectorCallsCount).toBe(1)
1174+
expect(itemSelectorCallsCount).toBe(3)
1175+
})
1176+
})
10541177
})
10551178

10561179
describe('createSelectorHook', () => {

0 commit comments

Comments
 (0)