feat(eslint-plugin): add prefer-useloader rule#3698
feat(eslint-plugin): add prefer-useloader rule#3698travisbreaks wants to merge 1 commit intopmndrs:masterfrom
Conversation
Prefer R3F's useLoader hook over Loader.load()/loadAsync() inside effects for automatic suspense integration and caching. Closes pmndrs#2701 (partial) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 43ffeac:
|
|
The problem is that many dynamic systems use effects or other things to load textures later in runtime. Triggering suspense might switch to a fallback causing a blink or even a entire section to unload depending on where the boundry is placed. |
|
Friendly ping. Let me know if this needs any changes or if there's anything blocking review. |
|
Good point. useLoader triggers Suspense, so for dynamic runtime loading (swapping textures mid-scene, progressively loading based on interaction), suspending could unmount existing content while the new asset loads. The rule targets the common case where someone loads at mount time via useEffect out of habit. For dynamic loading, an eslint-disable makes sense. Worth adding a "When not to use" section to the docs? Or would a rule option like |
Summary
Implements the
prefer-useloaderrule from the ESLint plugin RFC (#2701)..load()and.loadAsync()calls insideuseEffect/useLayoutEffectuseLoaderfor automatic Suspense integration and cachingrecommendedandallconfigsThis picks up from where #2724 left off (closed unmerged). No overlap with the
no-clone-in-loop/no-new-in-looprules already landed in #2710.Why prefer useLoader?
Calling
Loader.load()orLoader.loadAsync()inside effects bypasses React Suspense boundaries and the built-in caching thatuseLoaderprovides. This is one of the most common R3F pitfalls, documented in the pitfalls guide.Test plan
yarn testin eslint-plugin).load()/.loadAsync()outside effectsuseEffectanduseLayoutEffectPartial close of #2701.
Co-Authored-By: Claude Opus 4.6 (1M context) tadao@travisfixes.com