Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/website/content/docs/rules/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"dom-no-dangerously-set-innerhtml",
"dom-no-dangerously-set-innerhtml-with-children",
"dom-no-find-dom-node",
"dom-no-flush-sync",
"dom-no-missing-button-type",
"dom-no-missing-iframe-sandbox",
"dom-no-namespace",
Expand Down
1 change: 1 addition & 0 deletions apps/website/content/docs/rules/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ full: true
| [`no-dangerously-set-innerhtml-with-children`](./dom-no-dangerously-set-innerhtml-with-children) | 2️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML` and `children` at the same time. |
| [`no-dangerously-set-innerhtml`](./dom-no-dangerously-set-innerhtml) | 1️⃣ | `🔍` | Prevents DOM elements using `dangerouslySetInnerHTML`. |
| [`no-find-dom-node`](./dom-no-find-dom-node) | 2️⃣ | `🔍` | Prevents using `findDOMNode`. |
| [`no-flush-sync`](./dom-no-flush-sync) | 1️⃣ | `🔍` | Prevents using `flushSync`. |
| [`no-missing-button-type`](./dom-no-missing-button-type) | 1️⃣ | `🔍` | Enforces explicit `type` attribute for `button` elements. |
| [`no-missing-iframe-sandbox`](./dom-no-missing-iframe-sandbox) | 1️⃣ | `🔍` | Enforces explicit `sandbox` attribute for `iframe` elements. |
| [`no-namespace`](./dom-no-namespace) | 2️⃣ | `🔍` | Enforces the absence of a `namespace` in React elements. |
Expand Down
2 changes: 2 additions & 0 deletions packages/plugins/eslint-plugin-react-dom/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { name, version } from "../package.json";
import noDangerouslySetInnerHTML from "./rules/no-dangerously-set-innerhtml";
import noDangerouslySetInnerHTMLWithChildren from "./rules/no-dangerously-set-innerhtml-with-children";
import noFindDomNode from "./rules/no-find-dom-node";
import noFlushSync from "./rules/no-flush-sync";
import noMissingButtonType from "./rules/no-missing-button-type";
import noMissingIframeSandbox from "./rules/no-missing-iframe-sandbox";
import noNamespace from "./rules/no-namespace";
Expand All @@ -21,6 +22,7 @@ export const plugin = {
"no-dangerously-set-innerhtml": noDangerouslySetInnerHTML,
"no-dangerously-set-innerhtml-with-children": noDangerouslySetInnerHTMLWithChildren,
"no-find-dom-node": noFindDomNode,
"no-flush-sync": noFlushSync,
"no-missing-button-type": noMissingButtonType,
"no-missing-iframe-sandbox": noMissingIframeSandbox,
"no-namespace": noNamespace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,4 @@ class AutoSelectingInput extends Component {

## Further Reading

- [React: APIs findDOMNode](https://react.dev/reference/react-dom/findDOMNode)
- [React DOM: APIs findDOMNode](https://react.dev/reference/react-dom/findDOMNode)
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: no-flush-sync
---

**Full Name in `eslint-plugin-react-dom`**

```plain copy
react-dom/no-flush-sync
```

**Full Name in `@eslint-react/eslint-plugin`**

```plain copy
@eslint-react/dom/no-flush-sync
```

**Features**

`🔍`

## What it does

This rule reports usages of `flushSync`.

`flushSync` can significantly hurt performance, and may unexpectedly force pending Suspense boundaries to show their fallback state.

Most of the time, `flushSync` can be avoided, so use `flushSync` as a last resort.

## Examples

### Failing

```tsx
import { flushSync } from "react-dom";

flushSync(() => {
setSomething(123);
});
```

## Implementation

- [Rule source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom/src/rules/no-flush-sync.ts)
- [Test source](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom/src/rules/no-flush-sync.spec.ts)

## Further Reading

- [React DOM: APIs flushSync](https://react.dev/reference/react-dom/flushSync)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { allValid, ruleTester } from "../../../../../test";
import rule, { RULE_NAME } from "./no-flush-sync";

ruleTester.run(RULE_NAME, rule, {
invalid: [
{
code: /* tsx */ `
import { flushSync } from 'react-dom';

flushSync(() => {
setSomething(123);
});
`,
errors: [
{ messageId: "noFlushSync" },
],
},
{
code: /* tsx */ `
import reactDom from 'react-dom';

reactDom.flushSync(() => {
setSomething(123);
});
`,
errors: [
{ messageId: "noFlushSync" },
],
},
],
valid: [
...allValid,
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { RuleFeature } from "@eslint-react/shared";
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
import type { CamelCase } from "string-ts";

import { createRule } from "../utils";

export const RULE_NAME = "no-flush-sync";

export const RULE_FEATURES = [
"CHK",
] as const satisfies RuleFeature[];

export type MessageID = CamelCase<typeof RULE_NAME>;

export default createRule<[], MessageID>({
meta: {
type: "problem",
docs: {
description: "warns against using `flushSync`",
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
noFlushSync: "Using 'flushSync' is uncommon and can hurt the performance of your app.",
},
schema: [],
},
name: RULE_NAME,
create(context) {
if (!context.sourceCode.text.includes("flushSync")) return {};
return {
CallExpression(node) {
const { callee } = node;
switch (callee.type) {
case T.Identifier:
if (callee.name === "flushSync") {
context.report({ messageId: "noFlushSync", node });
}
return;
case T.MemberExpression:
if (callee.property.type === T.Identifier && callee.property.name === "flushSync") {
context.report({ messageId: "noFlushSync", node });
}
return;
}
},
};
},
defaultOptions: [],
});