task(sdk): Fix React hooks lint violations before upgrading eslint-plugin-react-hooks to v7
@fmontes is already working on this.
Since Mar 11, 2026.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
eslint-plugin-react-hooks v7 introduces stricter lint rules (react-hooks/set-state-in-effect, react-hooks/immutability, react-hooks/refs) that cause 11 lint errors across sdk-react and sdk-experiments.
The upgrade from 5.0.0 → ^7.0.1 was attempted in the remove-unnused-libs-exports-imports-enum branch and had to be reverted to unblock CI. These violations need to be resolved before re-attempting the upgrade.
Approach: All violations must be resolved by refactoring to follow React best practices — no eslint-disable suppression. Tests must be added or updated for every refactored hook/component.
sdk-react (7 errors)
| File | Line(s) | Rule | Issue |
|---|---|---|---|
DotCMSBlockEditorRenderer.tsx |
91 | set-state-in-effect |
setBlockEditorState() called synchronously in useEffect. Can derive with useMemo. |
Texts.tsx |
124–125 | immutability |
Mutating mark.attrs directly (setting className, deleting class). Should clone before mutating. |
DotCMSEditableText.tsx |
50 | set-state-in-effect |
setContent() in useEffect. Can derive state directly. |
DotCMSEditableText.tsx |
56 | set-state-in-effect |
setInitEditor() in useEffect. Can derive state directly. |
useCheckVisibleContent.ts |
30 | set-state-in-effect |
setHaveContent() in useLayoutEffect. |
useDotCMSShowWhen.ts |
39 | set-state-in-effect |
setShow() in useEffect. Can use useMemo. |
sdk-experiments (4 errors)
| File | Line(s) | Rule | Issue |
|---|---|---|---|
useExperimentVariant.ts |
35, 48, 60 | set-state-in-effect |
setShouldWaitForVariant() called synchronously in useEffect. |
memoize.ts |
44, 45, 48 | refs |
Accessing/writing ref.current during render in useMemoizedObject. |
Acceptance Criteria
Refactoring (one per violation)
-
DotCMSBlockEditorRenderer.tsx— ReplaceuseState+useEffectwithuseMemofor block validation state -
Texts.tsx— Clonemark.attrsbefore mutating (renameclass→className); no direct object mutation -
DotCMSEditableText.tsx:50— Derivecontentstate without synchronoussetStateinsideuseEffect -
DotCMSEditableText.tsx:56— DeriveinitEditorstate without synchronoussetStateinsideuseEffect -
useCheckVisibleContent.ts— Remove synchronoussetStatefromuseLayoutEffect -
useDotCMSShowWhen.ts— ReplaceuseState+useEffectwithuseMemo -
useExperimentVariant.ts— Remove synchronoussetShouldWaitForVariant()calls fromuseEffect -
memoize.ts— RefactoruseMemoizedObjectto avoid reading/writingref.currentduring render
Quality gates
- All fixes use proper React patterns — no
eslint-disablecomments for these rules - Tests added or updated for each refactored hook:
useCheckVisibleContent,useDotCMSShowWhen,useMemoizedObject,useExperimentVariant - Tests added or updated for refactored components:
DotCMSBlockEditorRenderer,Texts.TextBlock,DotCMSEditableText -
eslint-plugin-react-hooksupgraded from5.0.0to^7.0.1incore-web/package.json -
yarn nx run sdk-react:lintpasses with zero errors -
yarn nx run sdk-experiments:lintpasses with zero errors -
yarn nx run sdk-react:testpasses with zero failures -
yarn nx run sdk-experiments:testpasses with zero failures
Priority
Medium
Additional Context
Reproduction:
# In core-web/package.json, change eslint-plugin-react-hooks to "^7.0.1"
yarn install
yarn nx affected -t lint --base=origin/main --exclude='tag:skip:lint'
Key references:
- eslint-plugin-react-hooks v7 changelog
- These new rules align with React Compiler expectations and encourage patterns that avoid cascading renders
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.