Skip to content

Commit 988eaf1

Browse files
committed
refactor(rule): refactor no-unsafe-window-use and add docs
1 parent d9e135d commit 988eaf1

File tree

5 files changed

+1081
-166
lines changed

5 files changed

+1081
-166
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ Enable the rules that you would like to use.
131131
* [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md): Detect unescaped HTML entities, which might represent malformed tags
132132
* [react/no-unknown-property](docs/rules/no-unknown-property.md): Prevent usage of unknown DOM property (fixable)
133133
* [react/no-unsafe](docs/rules/no-unsafe.md): Prevent usage of unsafe lifecycle methods
134+
* [react/no-unsafe-window-use](docs/rules/no-unsafe-window-use.md): Prevent unsafe window use
134135
* [react/no-unused-prop-types](docs/rules/no-unused-prop-types.md): Prevent definitions of unused prop types
135136
* [react/no-unused-state](docs/rules/no-unused-state.md): Prevent definition of unused state fields
136137
* [react/no-will-update-set-state](docs/rules/no-will-update-set-state.md): Prevent usage of setState in componentWillUpdate

docs/rules/no-unsafe-window-use.md

Lines changed: 271 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,271 @@
1-
# Avoid unsafe global window use (react/no-unsafe-window-use)
1+
# Prevent unsafe window use (react/no-unsafe-window-use)
2+
3+
Rendering React apps in Node environments has become popular with the light of tools like [Gatsby][gatsby] and [Next.js][nextjs]. But in these environments, things that we are used to in the web, like `window`, are not available.
4+
5+
[gatsby]: http://gatsbyjs.org/
6+
[nextjs]: https://nextjs.org/
7+
8+
## Rule Details
9+
10+
The purpose of this rule is to prevent common errors related to the unsafe use of the `window` on apps intended to be rendered in environments other than the browser.
11+
12+
The following patterns are considered warnings:
13+
14+
```js
15+
window.bar = "baz"
16+
```
17+
18+
```js
19+
if (typeof window !== 'undefined') {
20+
} else {
21+
window.bar = "baz"
22+
}
23+
```
24+
25+
```js
26+
function bar() {
27+
window.something()
28+
}
29+
```
30+
31+
```js
32+
class Test {
33+
handle() {
34+
window.bar = "baz"
35+
}
36+
}
37+
```
38+
39+
```jsx
40+
class Test extends React.Component {
41+
render() {
42+
window.bar = "baz"
43+
return <button onClick={this.handleClick} />
44+
}
45+
};
46+
```
47+
48+
```jsx
49+
class Test extends React.Component {
50+
handleClick() {
51+
window.bar = "baz"
52+
}
53+
render() {
54+
this.handleClick()
55+
return <button onClick={this.handleClick} />
56+
}
57+
};
58+
```
59+
60+
```jsx
61+
class Test extends React.Component {
62+
handleClick() {
63+
window.bar = "baz"
64+
}
65+
otherHandler() {
66+
this.handleClick()
67+
}
68+
render() {
69+
this.otherHandler()
70+
return <button onClick={this.otherHandler} />
71+
}
72+
};
73+
```
74+
75+
```jsx
76+
function Test() {
77+
function handleClick() {
78+
window.bar = "baz"
79+
}
80+
handleClick()
81+
return (
82+
<button onClick={handleClick}>
83+
Click me!
84+
</button>
85+
)
86+
}
87+
```
88+
89+
```jsx
90+
function Test() {
91+
function handleClick() {
92+
window.bar = "baz"
93+
}
94+
function otherHandler() {
95+
handleClick()
96+
}
97+
otherHandler()
98+
return (
99+
<button onClick={otherHandler}>
100+
Click me!
101+
</button>
102+
)
103+
}
104+
```
105+
106+
```jsx
107+
class Test extends React.Component {
108+
constructor() {
109+
super()
110+
window.bar = "baz"
111+
}
112+
render() {
113+
return <div />
114+
}
115+
};
116+
```
117+
118+
```jsx
119+
class Test extends React.Component {
120+
constructor(props) {
121+
super(props)
122+
this.handler()
123+
}
124+
handler() {
125+
window.bar = "baz"
126+
}
127+
render() {
128+
return <div />
129+
}
130+
};
131+
```
132+
133+
The following patterns are **not** considered warnings:
134+
135+
```js
136+
if (typeof window !== 'undefined') {
137+
console.log(window)
138+
}
139+
```
140+
141+
```js
142+
typeof window !== "undefined" ? doSomething(window) : null
143+
```
144+
145+
```js
146+
typeof window !== "undefined" && doSomething(window)
147+
```
148+
149+
```jsx
150+
// Can use handler and window inside componentDidUpdate, componentDidMount and, componentWillUnmount
151+
152+
class Test extends React.Component {
153+
handleClick() {
154+
window.bar = "baz"
155+
}
156+
componentDidUpdate() {
157+
window.bar = "baz"
158+
this.handleClick()
159+
}
160+
componentDidMount() {
161+
window.bar = "baz"
162+
this.handleClick()
163+
}
164+
componentWillUnmount() {
165+
window.bar = "baz"
166+
this.handleClick()
167+
}
168+
render() {
169+
return <button onClick={this.handleClick} />
170+
}
171+
};
172+
```
173+
174+
```jsx
175+
// Can use handler and window inside useEffect, useLayoutEffect and, useCallback.
176+
function Test() {
177+
function handleClick() {
178+
window.bar = "baz"
179+
}
180+
useEffect(() => {
181+
window.bar = "baz"
182+
handleClick()
183+
})
184+
useLayoutEffect(() => {
185+
window.bar = "baz"
186+
handleClick()
187+
})
188+
const callback = useCallback(() => {
189+
window.bar = "baz"
190+
handleClick()
191+
}, [])
192+
return (
193+
<div>
194+
<button onClick={handleClick}>
195+
Click me!
196+
</button>
197+
<button onClick={callback}>
198+
Click me 2!
199+
</button>
200+
</div>
201+
)
202+
}
203+
```
204+
205+
```jsx
206+
// It is safe to use guarded handlers
207+
class Test extends React.Component {
208+
handleClick() {
209+
if (typeof window !== 'undefined') {
210+
window.bar = "baz"
211+
}
212+
}
213+
render() {
214+
this.handleClick()
215+
return <button onClick={this.handleClick} />
216+
}
217+
};
218+
```
219+
220+
```jsx
221+
// It is safe to use guarded handlers
222+
function Test() {
223+
function handleClick() {
224+
if (typeof window !== 'undefined') {
225+
window.bar = "baz"
226+
}
227+
}
228+
handleClick()
229+
return (
230+
<button onClick={handleClick}>
231+
Click me!
232+
</button>
233+
)
234+
}
235+
```
236+
237+
```jsx
238+
// Can use handler in other handlers as long as none of them is called directly.
239+
class Test extends React.Component {
240+
handleClick() {
241+
window.bar = "baz"
242+
}
243+
otherHandler() {
244+
this.handleClick()
245+
}
246+
render() {
247+
return <button onClick={this.otherHandler} />
248+
}
249+
};
250+
```
251+
252+
```jsx
253+
// Can use handler in other handlers as long as none of them is called directly.
254+
function Test() {
255+
const handleClick = () => {
256+
window.bar = "baz"
257+
}
258+
const otherHandler = () => {
259+
handleClick()
260+
}
261+
return (
262+
<button onClick={otherHandler}>
263+
Click me!
264+
</button>
265+
)
266+
}
267+
```
268+
269+
## When not to use
270+
271+
If your app will be rendered only on the frontend you can disable this rule.

index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ const allRules = {
7474
'no-unescaped-entities': require('./lib/rules/no-unescaped-entities'),
7575
'no-unknown-property': require('./lib/rules/no-unknown-property'),
7676
'no-unsafe': require('./lib/rules/no-unsafe'),
77+
'no-unsafe-window-use': require('./lib/rules/no-unsafe-window-use'),
7778
'no-unused-prop-types': require('./lib/rules/no-unused-prop-types'),
7879
'no-unused-state': require('./lib/rules/no-unused-state'),
7980
'no-will-update-set-state': require('./lib/rules/no-will-update-set-state'),
@@ -91,8 +92,7 @@ const allRules = {
9192
'state-in-constructor': require('./lib/rules/state-in-constructor'),
9293
'static-property-placement': require('./lib/rules/static-property-placement'),
9394
'style-prop-object': require('./lib/rules/style-prop-object'),
94-
'void-dom-elements-no-children': require('./lib/rules/void-dom-elements-no-children'),
95-
'no-unsafe-window-use': require('./lib/rules/no-unsafe-window-use')
95+
'void-dom-elements-no-children': require('./lib/rules/void-dom-elements-no-children')
9696
};
9797
/* eslint-enable */
9898

0 commit comments

Comments
 (0)