Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 06f97d1

Browse files
authored
fix: utils consuming iterables wrapped with iterateFormatted's populating the format function's index arg correctly to treat the iterable's current value as the first yield (#102)
1 parent 6a92373 commit 06f97d1

File tree

6 files changed

+82
-52
lines changed

6 files changed

+82
-52
lines changed

‎spec/tests/Iterate.spec.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ describe('`Iterate` component', () => {
672672
}
673673

674674
expect(renderFn.mock.calls.flat()).toStrictEqual(
675-
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_0'].map(value => ({
675+
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_1'].map(value => ({
676676
value,
677677
pendingFirst: false,
678678
done: false,

‎spec/tests/IterateMulti.spec.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ describe('`IterateMulti` hook', () => {
917917
{ value: 'a', pendingFirst: false, done: false, error: undefined },
918918
],
919919
[
920-
{ value: 'b_formatted_0', pendingFirst: false, done: false, error: undefined },
920+
{ value: 'b_formatted_1', pendingFirst: false, done: false, error: undefined },
921921
{ value: 'a', pendingFirst: false, done: false, error: undefined },
922922
],
923923
]);

‎spec/tests/useAsyncIter.spec.ts‎

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ describe('`useAsyncIter` hook', () => {
434434
gray(
435435
'When given an iterable with a `.value.current` property at any point, uses that as the current value and skips the pending stage'
436436
),
437-
() =>
437+
() =>{
438438
([{ initialValue: undefined }, { initialValue: '_' }] as const).forEach(
439439
({ initialValue }) => {
440440
it(
@@ -454,28 +454,21 @@ describe('`useAsyncIter` hook', () => {
454454

455455
const results: any[] = [];
456456

457-
for (const run of [
457+
for (const next of [
458+
() => renderedHook.rerender({ value: channel1 }),
459+
() => channel1.put('a'),
458460
() =>
459-
act(() =>
460-
renderedHook.rerender({
461-
value: channel1,
462-
})
463-
),
464-
() => act(() => channel1.put('a')),
465-
() =>
466-
act(() =>
467-
renderedHook.rerender({
468-
value: iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`),
469-
})
470-
),
471-
() => act(() => channel2.put('b')),
461+
renderedHook.rerender({
462+
value: iterateFormatted(channel2, (val, i) => `${val}_formatted_${i}`),
463+
}),
464+
() => channel2.put('b'),
472465
]) {
473-
await run();
466+
await act(next);
474467
results.push(renderedHook.result.current);
475468
}
476469

477470
expect(results).toStrictEqual(
478-
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_0'].map(value => ({
471+
['a_current', 'a', 'b_current_formatted_0', 'b_formatted_1'].map(value => ({
479472
value,
480473
pendingFirst: false,
481474
done: false,
@@ -485,7 +478,38 @@ describe('`useAsyncIter` hook', () => {
485478
}
486479
);
487480
}
488-
)
481+
);
482+
483+
it(gray('with a formatted iterable'), async () => {
484+
let timesRerendered = 0;
485+
const channel = Object.assign(new IteratorChannelTestHelper<string>(), {
486+
value: { current: 'a_current' },
487+
});
488+
489+
const renderedHook = await act(() =>
490+
renderHook(() => {
491+
timesRerendered++;
492+
return useAsyncIter(iterateFormatted(channel, (val, i) => `${val}_formatted_${i}`));
493+
})
494+
);
495+
expect(timesRerendered).toStrictEqual(1);
496+
expect(renderedHook.result.current).toStrictEqual({
497+
value: 'a_current_formatted_0',
498+
pendingFirst: false,
499+
done: false,
500+
error: undefined,
501+
});
502+
503+
await act(() => channel.put('a_next'));
504+
expect(timesRerendered).toStrictEqual(2);
505+
expect(renderedHook.result.current).toStrictEqual({
506+
value: 'a_next_formatted_1',
507+
pendingFirst: false,
508+
done: false,
509+
error: undefined,
510+
});
511+
});
512+
}
489513
);
490514

491515
it(gray('When unmounted will close the last active iterator it held'), async () => {
@@ -627,19 +651,19 @@ describe('`useAsyncIter` hook', () => {
627651

628652
const renderedHook = await act(() =>
629653
renderHook(
630-
({ formatInto }) => {
654+
({ formatTo }) => {
631655
timesRerendered++;
632-
return useAsyncIter(iterateFormatted(channel, _ => formatInto));
656+
return useAsyncIter(iterateFormatted(channel, _ => formatTo));
633657
},
634658
{
635-
initialProps: { formatInto: '' as string | null | undefined },
659+
initialProps: { formatTo: '' as string | null | undefined },
636660
}
637661
)
638662
);
639663

640664
await act(() => {
641665
channel.put('a');
642-
renderedHook.rerender({ formatInto: null });
666+
renderedHook.rerender({ formatTo: null });
643667
});
644668
expect(timesRerendered).toStrictEqual(3);
645669
expect(renderedHook.result.current).toStrictEqual({
@@ -651,7 +675,7 @@ describe('`useAsyncIter` hook', () => {
651675

652676
await act(() => {
653677
channel.put('b');
654-
renderedHook.rerender({ formatInto: undefined });
678+
renderedHook.rerender({ formatTo: undefined });
655679
});
656680
expect(timesRerendered).toStrictEqual(5);
657681
expect(renderedHook.result.current).toStrictEqual({

‎spec/tests/useAsyncIterMulti.spec.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ describe('`useAsyncIterMulti` hook', () => {
632632
{ value: 'a', pendingFirst: false, done: false, error: undefined },
633633
],
634634
[
635-
{ value: 'b_formatted_0', pendingFirst: false, done: false, error: undefined },
635+
{ value: 'b_formatted_1', pendingFirst: false, done: false, error: undefined },
636636
{ value: 'a', pendingFirst: false, done: false, error: undefined },
637637
],
638638
]);

‎src/common/useAsyncItersImperatively/index.ts‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,20 @@ const useAsyncItersImperatively: {
120120
return existingIterState.currState;
121121
}
122122

123-
const formattedIter: AsyncIterable<unknown> = (() => {
124-
let iterationIdx = 0;
125-
return asyncIterSyncMap(baseIter, value => iterState.formatFn(value, iterationIdx++));
126-
})();
127-
128123
const inputWithMaybeCurrentValue = input as typeof input & {
129124
value?: AsyncIterableSubject<unknown>['value'];
130125
};
131126

132-
let pendingFirst;
127+
let iterationIdx: number;
128+
let pendingFirst: boolean;
133129
let startingValue;
134130

135131
if (inputWithMaybeCurrentValue.value) {
132+
iterationIdx = 1; // If source has a current value, it should have been the "first iteration" already, so in that case the right up next one here is *the second* already (index of 1)
136133
pendingFirst = false;
137134
startingValue = inputWithMaybeCurrentValue.value.current;
138135
} else {
136+
iterationIdx = 0;
139137
pendingFirst = true;
140138
startingValue =
141139
i < ref.current.currResults.length
@@ -147,11 +145,17 @@ const useAsyncItersImperatively: {
147145
);
148146
}
149147

148+
const formattedIter: AsyncIterable<unknown> = asyncIterSyncMap(baseIter, value =>
149+
iterState.formatFn(value, iterationIdx++)
150+
);
151+
150152
const destroyFn = iterateAsyncIterWithCallbacks(formattedIter, startingValue, next => {
151153
iterState.currState = { pendingFirst: false, ...next };
152-
const newPrevResults = ref.current.currResults.slice(0); // Using `.slice(0)` in attempt to copy the array faster than `[...ref.current.currResults]` would
153-
newPrevResults[i] = iterState.currState;
154-
ref.current.currResults = newPrevResults as typeof ref.current.currResults;
154+
ref.current.currResults = (() => {
155+
const newResults = ref.current.currResults.slice(0); // Using `.slice(0)` in attempt to copy the array faster than `[...ref.current.currResults]` would
156+
newResults[i] = iterState.currState;
157+
return newResults as typeof ref.current.currResults;
158+
})();
155159
onYieldCb(ref.current.currResults);
156160
});
157161

‎src/useAsyncIter/index.ts‎

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from '../common/ReactAsyncIterable.js';
1212
import { iterateAsyncIterWithCallbacks } from '../common/iterateAsyncIterWithCallbacks.js';
1313
import { callOrReturn } from '../common/callOrReturn.js';
14+
import { asyncIterSyncMap } from '../common/asyncIterSyncMap.js';
1415
import { type Iterate } from '../Iterate/index.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
1516
import { type iterateFormatted } from '../iterateFormatted/index.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
1617

@@ -148,19 +149,19 @@ const useAsyncIter: {
148149
const iterSourceRefToUse =
149150
latestInputRef.current[reactAsyncIterSpecialInfoSymbol]?.origSource ?? latestInputRef.current;
150151

151-
useMemo((): void => {
152-
const latestInputRefCurrent = latestInputRef.current!;
152+
const latestInputRefCurrent = latestInputRef.current!;
153153

154-
letvalue;
154+
useMemo((): void=>{
155155
let pendingFirst;
156+
let value;
156157

157158
if (latestInputRefCurrent.value) {
158-
value = latestInputRefCurrent.value.current;
159159
pendingFirst = false;
160+
value = latestInputRefCurrent.value.current;
160161
} else {
161162
const prevSourceLastestVal = stateRef.current.value;
162-
value = prevSourceLastestVal;
163163
pendingFirst = true;
164+
value = prevSourceLastestVal;
164165
}
165166

166167
stateRef.current = {
@@ -172,22 +173,23 @@ const useAsyncIter: {
172173
}, [iterSourceRefToUse]);
173174

174175
useEffect(() => {
175-
let iterationIdx = 0;
176+
const formattedIter = (() => {
177+
let iterationIdx = latestInputRefCurrent.value ? 1 : 0; // If source has a current value, it should have been the "first iteration" already, so in that case the right up next one here is *the second* already (index of 1)
176178

177-
return iterateAsyncIterWithCallbacks(iterSourceRefToUse, stateRef.current.value,next => {
178-
const possibleGivenFormatFn =
179-
latestInputRef.current?.[reactAsyncIterSpecialInfoSymbol]?.formatFn;
179+
return asyncIterSyncMap(iterSourceRefToUse, value => {
180+
const possibleGivenFormatFn =
181+
latestInputRef.current?.[reactAsyncIterSpecialInfoSymbol]?.formatFn;
180182

181-
const formattedValue = possibleGivenFormatFn
182-
? possibleGivenFormatFn(next.value, iterationIdx++)
183-
: next.value;
183+
const formattedValue = possibleGivenFormatFn
184+
? possibleGivenFormatFn(value, iterationIdx++)
185+
: value;
184186

185-
stateRef.current = {
186-
...next,
187-
pendingFirst: false,
188-
value: formattedValue,
189-
};
187+
return formattedValue;
188+
});
189+
})();
190190

191+
return iterateAsyncIterWithCallbacks(formattedIter, stateRef.current.value, next => {
192+
stateRef.current = { ...next, pendingFirst: false };
191193
rerender();
192194
});
193195
}, [iterSourceRefToUse]);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /