Skip to content

Commit af4855c

Browse files
committed
Pass Suspense config to startTransition
...instead of `useTransition`. This avoids the problem of having to bind the config object to `startTransition`, invalidating downstream memoizations.
1 parent 35280c5 commit af4855c

File tree

2 files changed

+47
-54
lines changed

2 files changed

+47
-54
lines changed

packages/react-reconciler/src/ReactFiberHooks.js

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,50 +1172,34 @@ function updateDeferredValue<T>(
11721172
return prevValue;
11731173
}
11741174

1175+
function startTransition(setPending, callback, config) {
1176+
setPending(true);
1177+
Scheduler.unstable_next(() => {
1178+
const previousConfig = ReactCurrentBatchConfig.suspense;
1179+
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1180+
try {
1181+
setPending(false);
1182+
callback();
1183+
} finally {
1184+
ReactCurrentBatchConfig.suspense = previousConfig;
1185+
}
1186+
});
1187+
}
1188+
11751189
function mountTransition(
11761190
config: SuspenseConfig | void | null,
11771191
): [(() => void) => void, boolean] {
11781192
const [isPending, setPending] = mountState(false);
1179-
const startTransition = mountCallback(
1180-
callback => {
1181-
setPending(true);
1182-
Scheduler.unstable_next(() => {
1183-
const previousConfig = ReactCurrentBatchConfig.suspense;
1184-
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1185-
try {
1186-
setPending(false);
1187-
callback();
1188-
} finally {
1189-
ReactCurrentBatchConfig.suspense = previousConfig;
1190-
}
1191-
});
1192-
},
1193-
[config, isPending],
1194-
);
1195-
return [startTransition, isPending];
1193+
const startTransitionRef = mountRef(startTransition.bind(null, setPending));
1194+
return [startTransitionRef.current, isPending];
11961195
}
11971196

11981197
function updateTransition(
11991198
config: SuspenseConfig | void | null,
12001199
): [(() => void) => void, boolean] {
1201-
const [isPending, setPending] = updateState(false);
1202-
const startTransition = updateCallback(
1203-
callback => {
1204-
setPending(true);
1205-
Scheduler.unstable_next(() => {
1206-
const previousConfig = ReactCurrentBatchConfig.suspense;
1207-
ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1208-
try {
1209-
setPending(false);
1210-
callback();
1211-
} finally {
1212-
ReactCurrentBatchConfig.suspense = previousConfig;
1213-
}
1214-
});
1215-
},
1216-
[config, isPending],
1217-
);
1218-
return [startTransition, isPending];
1200+
const [isPending] = updateState(false);
1201+
const startTransitionRef = updateRef();
1202+
return [startTransitionRef.current, isPending];
12191203
}
12201204

12211205
function dispatchAction<S, A>(

packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,16 +1977,18 @@ describe('ReactHooksWithNoopRenderer', () => {
19771977
it.experimental(
19781978
'delays showing loading state until after timeout',
19791979
async () => {
1980+
const SUSPENSE_CONFIG = {
1981+
timeoutMs: 1000,
1982+
};
1983+
19801984
let transition;
19811985
function App() {
19821986
const [show, setShow] = useState(false);
1983-
const [startTransition, isPending] = useTransition({
1984-
timeoutMs: 1000,
1985-
});
1987+
const [startTransition, isPending] = useTransition();
19861988
transition = () => {
19871989
startTransition(() => {
19881990
setShow(true);
1989-
});
1991+
}, SUSPENSE_CONFIG);
19901992
};
19911993
return (
19921994
<Suspense
@@ -2043,17 +2045,19 @@ describe('ReactHooksWithNoopRenderer', () => {
20432045
it.experimental(
20442046
'delays showing loading state until after busyDelayMs + busyMinDurationMs',
20452047
async () => {
2048+
const SUSPENSE_CONFIG = {
2049+
busyDelayMs: 1000,
2050+
busyMinDurationMs: 2000,
2051+
};
2052+
20462053
let transition;
20472054
function App() {
20482055
const [show, setShow] = useState(false);
2049-
const [startTransition, isPending] = useTransition({
2050-
busyDelayMs: 1000,
2051-
busyMinDurationMs: 2000,
2052-
});
2056+
const [startTransition, isPending] = useTransition();
20532057
transition = () => {
20542058
startTransition(() => {
20552059
setShow(true);
2056-
});
2060+
}, SUSPENSE_CONFIG);
20572061
};
20582062
return (
20592063
<Suspense
@@ -2113,13 +2117,15 @@ describe('ReactHooksWithNoopRenderer', () => {
21132117
);
21142118

21152119
it.experimental('always returns the same startTransition', async () => {
2120+
const SUSPENSE_CONFIG = {
2121+
busyDelayMs: 1000,
2122+
busyMinDurationMs: 2000,
2123+
};
2124+
21162125
let transition;
21172126
function App() {
21182127
const [step, setStep] = useState(0);
2119-
const [startTransition, isPending] = useTransition({
2120-
busyDelayMs: 1000,
2121-
busyMinDurationMs: 2000,
2122-
});
2128+
const [startTransition, isPending] = useTransition();
21232129
// Log whenever startTransition changes
21242130
useEffect(
21252131
() => {
@@ -2130,7 +2136,7 @@ describe('ReactHooksWithNoopRenderer', () => {
21302136
transition = () => {
21312137
startTransition(() => {
21322138
setStep(n => n + 1);
2133-
});
2139+
}, SUSPENSE_CONFIG);
21342140
};
21352141
return (
21362142
<Suspense fallback={<Text text="Loading..." />}>
@@ -2175,12 +2181,12 @@ describe('ReactHooksWithNoopRenderer', () => {
21752181
});
21762182

21772183
it.experimental(
2178-
'can update suspense config (without changing startTransition)',
2184+
'can pass different suspense configs per transition',
21792185
async () => {
21802186
let transition;
21812187
function App({timeoutMs}) {
21822188
const [step, setStep] = useState(0);
2183-
const [startTransition, isPending] = useTransition({timeoutMs});
2189+
const [startTransition, isPending] = useTransition();
21842190
// Log whenever startTransition changes
21852191
useEffect(
21862192
() => {
@@ -2189,9 +2195,12 @@ describe('ReactHooksWithNoopRenderer', () => {
21892195
[startTransition],
21902196
);
21912197
transition = () => {
2192-
startTransition(() => {
2193-
setStep(n => n + 1);
2194-
});
2198+
startTransition(
2199+
() => {
2200+
setStep(n => n + 1);
2201+
},
2202+
{timeoutMs},
2203+
);
21952204
};
21962205
return (
21972206
<Suspense fallback={<Text text="Loading..." />}>

0 commit comments

Comments
 (0)