[Perf] Teact: Avoid redundant renders when updating state with a callback

This commit is contained in:
Alexander Zinchuk 2023-01-22 18:12:37 +01:00
parent 6213ed60d5
commit c6bd762a4c

View File

@ -473,39 +473,41 @@ export function useState<T>(initial?: T, debugKey?: string): [T, StateHookSetter
value: initial, value: initial,
nextValue: initial, nextValue: initial,
setter: ((componentInstance) => (newValue: ((current: T) => T) | T) => { setter: ((componentInstance) => (newValue: ((current: T) => T) | T) => {
if (byCursor[cursor].nextValue !== newValue) { if (typeof newValue === 'function') {
byCursor[cursor].nextValue = typeof newValue === 'function' newValue = (newValue as (current: T) => T)(byCursor[cursor].value);
? (newValue as (current: T) => T)(byCursor[cursor].value) }
: newValue;
if (!componentInstance.prepareForFrame || !componentInstance.forceUpdate) { if (byCursor[cursor].nextValue === newValue) {
componentInstance.prepareForFrame = throttleWithPrimaryRaf( return;
() => prepareComponentForFrame(componentInstance), }
byCursor[cursor].nextValue = newValue;
if (!componentInstance.prepareForFrame || !componentInstance.forceUpdate) {
componentInstance.prepareForFrame = throttleWithPrimaryRaf(
() => prepareComponentForFrame(componentInstance),
);
componentInstance.forceUpdate = throttleWithRaf(
() => forceUpdateComponent(componentInstance),
);
}
componentInstance.prepareForFrame();
componentInstance.forceUpdate();
if (DEBUG_MORE) {
if (componentInstance.name !== 'TeactNContainer') {
// eslint-disable-next-line no-console
console.log(
'[Teact.useState]',
componentInstance.name,
// `componentInstance.Component` may be set to `null` by GC helper
componentInstance.Component && (componentInstance.Component as FC_withDebug).DEBUG_contentComponentName
? `> ${(componentInstance.Component as FC_withDebug).DEBUG_contentComponentName}`
: '',
`State update at cursor #${cursor}${debugKey ? ` (${debugKey})` : ''}, next value: `,
byCursor[cursor].nextValue,
); );
componentInstance.forceUpdate = throttleWithRaf(
() => forceUpdateComponent(componentInstance),
);
}
componentInstance.prepareForFrame();
componentInstance.forceUpdate();
if (DEBUG_MORE) {
if (componentInstance.name !== 'TeactNContainer') {
// eslint-disable-next-line no-console
console.log(
'[Teact.useState]',
componentInstance.name,
// `componentInstance.Component` may be set to `null` by GC helper
componentInstance.Component && (componentInstance.Component as FC_withDebug).DEBUG_contentComponentName
? `> ${(componentInstance.Component as FC_withDebug).DEBUG_contentComponentName}`
: '',
debugKey
? `State update for ${debugKey}, next value: `
: `State update at cursor #${cursor}, next value: `,
byCursor[cursor].nextValue,
);
}
} }
} }
})(renderingInstance), })(renderingInstance),