Skip to content

[New] : Avoid unsafe global window use #2692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ Enable the rules that you would like to use.
* [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md): Detect unescaped HTML entities, which might represent malformed tags
* [react/no-unknown-property](docs/rules/no-unknown-property.md): Prevent usage of unknown DOM property (fixable)
* [react/no-unsafe](docs/rules/no-unsafe.md): Prevent usage of unsafe lifecycle methods
* [react/no-unsafe-window-use](docs/rules/no-unsafe-window-use.md): Prevent unsafe window use
* [react/no-unused-prop-types](docs/rules/no-unused-prop-types.md): Prevent definitions of unused prop types
* [react/no-unused-state](docs/rules/no-unused-state.md): Prevent definition of unused state fields
* [react/no-will-update-set-state](docs/rules/no-will-update-set-state.md): Prevent usage of setState in componentWillUpdate
Expand Down
271 changes: 271 additions & 0 deletions docs/rules/no-unsafe-window-use.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
# Prevent unsafe window use (react/no-unsafe-window-use)

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.

[gatsby]: http://gatsbyjs.org/
[nextjs]: https://nextjs.org/

## Rule Details

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.

The following patterns are considered warnings:

```js
window.bar = "baz"
```

```js
if (typeof window !== 'undefined') {
} else {
window.bar = "baz"
}
```

```js
function bar() {
window.something()
}
```

```js
class Test {
handle() {
window.bar = "baz"
}
}
```

```jsx
class Test extends React.Component {
render() {
window.bar = "baz"
return <button onClick={this.handleClick} />
}
};
```

```jsx
class Test extends React.Component {
handleClick() {
window.bar = "baz"
}
render() {
this.handleClick()
return <button onClick={this.handleClick} />
}
};
```

```jsx
class Test extends React.Component {
handleClick() {
window.bar = "baz"
}
otherHandler() {
this.handleClick()
}
render() {
this.otherHandler()
return <button onClick={this.otherHandler} />
}
};
```

```jsx
function Test() {
function handleClick() {
window.bar = "baz"
}
handleClick()
return (
<button onClick={handleClick}>
Click me!
</button>
)
}
```

```jsx
function Test() {
function handleClick() {
window.bar = "baz"
}
function otherHandler() {
handleClick()
}
otherHandler()
return (
<button onClick={otherHandler}>
Click me!
</button>
)
}
```

```jsx
class Test extends React.Component {
constructor() {
super()
window.bar = "baz"
}
render() {
return <div />
}
};
```

```jsx
class Test extends React.Component {
constructor(props) {
super(props)
this.handler()
}
handler() {
window.bar = "baz"
}
render() {
return <div />
}
};
```

The following patterns are **not** considered warnings:

```js
if (typeof window !== 'undefined') {
console.log(window)
}
```

```js
typeof window !== "undefined" ? doSomething(window) : null
```

```js
typeof window !== "undefined" && doSomething(window)
```

```jsx
// Can use handler and window inside componentDidUpdate, componentDidMount and, componentWillUnmount

class Test extends React.Component {
handleClick() {
window.bar = "baz"
}
componentDidUpdate() {
window.bar = "baz"
this.handleClick()
}
componentDidMount() {
window.bar = "baz"
this.handleClick()
}
componentWillUnmount() {
window.bar = "baz"
this.handleClick()
}
render() {
return <button onClick={this.handleClick} />
}
};
```

```jsx
// Can use handler and window inside useEffect, useLayoutEffect and, useCallback.
function Test() {
function handleClick() {
window.bar = "baz"
}
useEffect(() => {
window.bar = "baz"
handleClick()
})
useLayoutEffect(() => {
window.bar = "baz"
handleClick()
})
const callback = useCallback(() => {
window.bar = "baz"
handleClick()
}, [])
return (
<div>
<button onClick={handleClick}>
Click me!
</button>
<button onClick={callback}>
Click me 2!
</button>
</div>
)
}
```

```jsx
// It is safe to use guarded handlers
class Test extends React.Component {
handleClick() {
if (typeof window !== 'undefined') {
window.bar = "baz"
}
}
render() {
this.handleClick()
return <button onClick={this.handleClick} />
}
};
```

```jsx
// It is safe to use guarded handlers
function Test() {
function handleClick() {
if (typeof window !== 'undefined') {
window.bar = "baz"
}
}
handleClick()
return (
<button onClick={handleClick}>
Click me!
</button>
)
}
```

```jsx
// Can use handler in other handlers as long as none of them is called directly.
class Test extends React.Component {
handleClick() {
window.bar = "baz"
}
otherHandler() {
this.handleClick()
}
render() {
return <button onClick={this.otherHandler} />
}
};
```

```jsx
// Can use handler in other handlers as long as none of them is called directly.
function Test() {
const handleClick = () => {
window.bar = "baz"
}
const otherHandler = () => {
handleClick()
}
return (
<button onClick={otherHandler}>
Click me!
</button>
)
}
```

## When not to use

If your app will be rendered only on the frontend you can disable this rule.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const allRules = {
'no-unescaped-entities': require('./lib/rules/no-unescaped-entities'),
'no-unknown-property': require('./lib/rules/no-unknown-property'),
'no-unsafe': require('./lib/rules/no-unsafe'),
'no-unsafe-window-use': require('./lib/rules/no-unsafe-window-use'),
'no-unused-prop-types': require('./lib/rules/no-unused-prop-types'),
'no-unused-state': require('./lib/rules/no-unused-state'),
'no-will-update-set-state': require('./lib/rules/no-will-update-set-state'),
Expand Down
Loading