Commit 7ffba1c
authored
fix runaway effect in useTranslation (#1889)
In the useTranslation.js hook, the loadNamespaces function itself is asynchronous (it fetches translations). The mechanism that triggers the state update (and thus the re-render) is the callback provided to loadNamespaces.
Here is the relevant code block from useTranslation.js:
// ...
const [loadCount, setLoadCount] = useState(0); // <--- 1. State hook
// ...
useEffect(() => {
if (i18n && !ready && !useSuspense) {
const onLoaded = () => setLoadCount((c) => c + 1); // <--- 2. Callback updating state
if (props.lng) {
loadLanguages(i18n, props.lng, namespaces, onLoaded);
} else {
loadNamespaces(i18n, namespaces, onLoaded); // <--- 3. Trigger
}
}
}, [i18n, props.lng, namespaces, ready, useSuspense, loadCount]); // <--- 4. Dependency array
The Cycle of Runaway Effect:
1. Render: useTranslation(['ns1']) is called. A new array ['ns1'] is created.
2. Memoization (Broken): namespaces is memoized with useMemo, but it depends on ns. Since ns is a new reference, namespaces becomes a new reference.
3. Effect: The useEffect has namespaces in its dependency array. React sees it changed, so it runs the effect.
4. Logic: Inside the effect, if !ready (translations not loaded yet), it calls loadNamespaces.
5. Callback: It passes onLoaded, which calls setLoadCount(c => c + 1).
6. Update: loadNamespaces might finish immediately (if cached) or later. It calls onLoaded.
7. Re-render: setLoadCount triggers a re-render of the component.
8. Loop: Back to Step 1. The component re-renders, creates a new ['ns1'] array, namespaces changes, effect runs again, state updates again... Infinite Loop.
By stabilizing namespaces, the namespaces reference remains the same across renders even if ns is a new array object. Therefore, useEffect sees no change in dependencies and doesn't run again, breaking the loop.1 parent 4a3623c commit 7ffba1c
2 files changed
+38
-4
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
50 | 49 | | |
51 | 50 | | |
52 | 51 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
312 | 347 | | |
0 commit comments