Skip to content

Commit a3d8f86

Browse files
committed
Track upstream value across renders even when in sync
`useCachedValue`'s during-render reset only updated `previousValue.current` inside the branch that observes an external value change. After a debounced save echoed the local edit back as the new upstream value, the ref stayed pointing at the pre-save value. The next local edit then made the next render look like an external change (`previousValue.current !== value` while `value !== cachedValue`), which fired `onReset` and discarded the edit. Restore the post-render effect that unconditionally syncs `previousValue.current` to the latest committed `value`, so a local edit following a debounced save reaches `cachedValue` instead of being reset back. REDMINE-21261
1 parent 935ffec commit a3d8f86

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

entry_types/scrolled/package/spec/frontend/inlineEditing/useCachedValue-spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,26 @@ describe('useCachedValue', () => {
7979
expect(listener).not.toHaveBeenCalled();
8080
});
8181

82+
it('does not reset a follow-up local edit after passed value caught up to a previous one', () => {
83+
const listener = jest.fn();
84+
const {result, rerender} = renderHook(
85+
({value}) => useCachedValue(value, {
86+
onReset: listener
87+
}),
88+
{initialProps: {value: 'value'}}
89+
);
90+
91+
let [, setValue] = result.current;
92+
act(() => setValue('new value'));
93+
rerender({value: 'new value'});
94+
[, setValue] = result.current;
95+
act(() => setValue('newer value'));
96+
97+
const [cachedValue] = result.current;
98+
expect(cachedValue).toBe('newer value');
99+
expect(listener).not.toHaveBeenCalled();
100+
});
101+
82102
it('calls onDebouncedChange after value has not been set for given delay', () => {
83103
const listener = jest.fn();
84104
const {result} = renderHook(() => useCachedValue('value', {

entry_types/scrolled/package/src/frontend/inlineEditing/useCachedValue.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ export function useCachedValue(value, {
2020
previousValue.current = value;
2121
}
2222

23+
// Track the upstream value across renders. The branch above only
24+
// assigns when an external change is observed; without this effect,
25+
// a render that sees `value` already in sync with `cachedValue` (a
26+
// local edit echoed back via `onDebouncedChange`) would leave
27+
// `previousValue.current` stale. The next local edit would then
28+
// misread that stale value as an external change and overwrite the
29+
// edit with `onReset`.
30+
useEffect(() => {
31+
previousValue.current = value;
32+
});
33+
2334
const debouncedHandler = useDebouncedCallback(onDebouncedChange, delay);
2435

2536
const setValue = useCallback(value => {

0 commit comments

Comments
 (0)