Skip to content

Commit ad51a26

Browse files
docs(rules): updated rules docs
1 parent 1e43379 commit ad51a26

File tree

6 files changed

+176
-4
lines changed

6 files changed

+176
-4
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
This ESLint plugin currently contains 2 rules:
66

7-
- prefer-destructured-optionals
8-
- ensure-matching-remove-event-listener
7+
- [prefer-destructured-optionals](./docs/rules/prefer-destructured-optionals.md)
8+
- [valid-event-listener](./docs/rules/valid-event-listener.md)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Enforces a specific style for the anatomy of a function signature
2+
3+
This rule enforce that required parameters should always be placed at the start of the function signature and optional parameters should always be placed at the end of the function signature, in the form of a destructured object.
4+
5+
## Fail
6+
7+
```js
8+
const myFn = (param1, optionalParam = "x") => {
9+
console.log(param1, optionalParam);
10+
};
11+
```
12+
13+
```js
14+
const myFn = (param1, { optionalParam1 = "default" }, param2) => {
15+
console.log(param1, optionalParam1, param2);
16+
};
17+
```
18+
19+
## Pass
20+
21+
```js
22+
const myFn = (param1, param2, { optionalParam = "x" }) => {
23+
console.log(param1, param2, optionalParam);
24+
};
25+
```

docs/rules/valid-event-listener.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Enforces best practices around addEventListener method
2+
3+
This rule enforces 3 things:
4+
5+
- enforces the use of a useEventListener hook from a hooks library instead of manually adding and removing event listeners (_optional_. `true` by default)
6+
- every addEventListener should have a cleanup function
7+
- every addEventListener should have a matching removeEventListener in the returned cleanup function of same useEffect block
8+
- addEventListener methods should not be called conditionally
9+
10+
## Options
11+
12+
### requireUseEventListenerHook
13+
14+
Type: `boolean`\
15+
Default: `true`
16+
17+
A lot of react-hooks libraries provide a `useEventListener` hook that simplifies event-listeners management. This rule can enforce the use of such a hook instead of manually adding and removing event listeners.
18+
19+
This option is set to `true` by default. Setting this to false will disable this check but the other checks around addEventListener usage correctness will still be enforced.
20+
21+
## Fail
22+
23+
```js
24+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
25+
useEffect(() => {
26+
doThis();
27+
if (x) window.document.addEventListener("keydown", handleUserKeyPress);
28+
}, []);
29+
```
30+
31+
```js
32+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
33+
useEffect(() => {
34+
doThis();
35+
x && window.document.addEventListener("keydown", handleUserKeyPress);
36+
}, []);
37+
```
38+
39+
```js
40+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
41+
useEffect(() => {
42+
doThis();
43+
if (x) {
44+
window.document.addEventListener("keydown", handleUserKeyPress);
45+
}
46+
}, []);
47+
```
48+
49+
```js
50+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
51+
useEffect(() => {
52+
doThis();
53+
if (x) {
54+
x();
55+
} else {
56+
window.document.addEventListener("keydown", handleUserKeyPress);
57+
}
58+
}, []);
59+
```
60+
61+
```js
62+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
63+
useEffect(() => {
64+
doThis();
65+
if (x) {
66+
doThisMore();
67+
}
68+
window.document.addEventListener("keydown", handleUserKeyPress);
69+
}, []);
70+
```
71+
72+
```js
73+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
74+
useEffect(() => {
75+
doThis();
76+
if (x) {
77+
doThisMore();
78+
}
79+
window.document.addEventListener("keydown", handleUserKeyPress);
80+
doMoreOfThis();
81+
return () => {
82+
if (x) {
83+
doThisMore();
84+
}
85+
doThatAfter();
86+
};
87+
}, []);
88+
```
89+
90+
```js
91+
// eslint fsecond/valid-event-listener: 2
92+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
93+
useEffect(() => {
94+
window.addEventListener("keydown", handleUserKeyPress);
95+
return () => {
96+
window.removeEventListener("keydown", handleUserKeyPress);
97+
};
98+
}, []);
99+
```
100+
101+
## Pass
102+
103+
```js
104+
// eslint fsecond/valid-event-listener: 2
105+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
106+
useEventListener("scroll", onScroll);
107+
```
108+
109+
```js
110+
// eslint fsecond/valid-event-listener: 2
111+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
112+
useEventListener("visibilitychange", onVisibilityChange, documentRef);
113+
```
114+
115+
```js
116+
// eslint fsecond/valid-event-listener: 2
117+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
118+
useEventListener("click", onClick, buttonRef);
119+
```
120+
121+
```js
122+
// eslint fsecond/valid-event-listener: 2
123+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
124+
useEffect(() => {
125+
return () => {
126+
window.removeEventListener("keydown", handleUserKeyPress);
127+
};
128+
}, []);
129+
```
130+
131+
```js
132+
// eslint fsecond/valid-event-listener: 2
133+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": true}]
134+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
135+
useEffect(() => {
136+
refcurrent = value;
137+
}, [value]);
138+
```
139+
140+
```js
141+
// eslint fsecond/valid-event-listener: [2, {"requireUseEventListenerHook": false}]
142+
useEffect(() => {
143+
window.document.addEventListener("keydown", handleUserKeyPress);
144+
return () => {
145+
window.document.removeEventListener("keydown", handleUserKeyPress);
146+
};
147+
}, []);
148+
```

src/rules/prefer-destructured-optionals.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export default createEslintRule<Options, MessageIds>({
1111
docs: {
1212
description:
1313
"enforce placing optional parameters on a destructured object instead of the function signature itself",
14-
recommended: "stylistic",
1514
},
1615
schema: [],
1716
messages: {

src/rules/valid-event-listener.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { RuleTester } from "@typescript-eslint/utils/ts-eslint";
22
import { test } from "vitest";
33
import rule, { RULE_NAME } from "./valid-event-listener";
4+
45
const casesWithRequireUseEventListenerHookOption = {
56
valids: [
67
{

src/rules/valid-event-listener.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export default createEslintRule<Options, MessageIds>({
1414
type: "problem",
1515
docs: {
1616
description: "Enforces best practices around addEventListener method.",
17-
recommended: "recommended",
1817
},
1918
schema: [
2019
{

0 commit comments

Comments
 (0)