Skip to content

Commit

Permalink
Merge pull request #2075 from sergei-startsev/no-unsafe-aliases
Browse files Browse the repository at this point in the history
Adjust `no-unsafe` rule to handle all unsafe life-cycle methods
  • Loading branch information
ljharb committed Dec 11, 2018
2 parents 35c0b4d + 8d2c7a9 commit 4583342
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 21 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -119,7 +119,7 @@ Enable the rules that you would like to use.
* [react/no-this-in-sfc](docs/rules/no-this-in-sfc.md): Prevent using `this` in stateless functional components
* [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md): Prevent invalid characters from appearing in markup
* [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_` methods
* [react/no-unsafe](docs/rules/no-unsafe.md): Prevent usage of unsafe lifecycle methods
* [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 definitions of unused state properties
* [react/no-will-update-set-state](docs/rules/no-will-update-set-state.md): Prevent usage of `setState` in `componentWillUpdate`
Expand Down
54 changes: 52 additions & 2 deletions docs/rules/no-unsafe.md
@@ -1,12 +1,15 @@
# Prevent usage of `UNSAFE_` methods (react/no-unsafe)
# Prevent usage of unsafe lifecycle methods (react/no-unsafe)

Certain legacy lifecycle methods are [unsafe for use in async React applications][async_rendering] and cause warnings in [_strict mode_][strict_mode]. These also happen to be the lifecycles that cause the most [confusion within the React community][component_lifecycle_changes].

[async_rendering]: https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
[strict_mode]: https://reactjs.org/docs/strict-mode.html#identifying-unsafe-lifecycles
[component_lifecycle_changes]: https://reactjs.org/blog/2018/03/29/react-v-16-3.html#component-lifecycle-changes

The rule checks the following methods: `UNSAFE_componentWillMount`, `UNSAFE_componentWillReceiveProps`, `UNSAFE_componentWillUpdate`.
The rule checks the following methods:
- `componentWillMount` (and `UNSAFE_componentWillMount` alias)
- `componentWillReceiveProps` (and `UNSAFE_componentWillReceiveProps` alias)
- `componentWillUpdate` (and `UNSAFE_componentWillUpdate` alias)

## Rule Details

Expand Down Expand Up @@ -45,3 +48,50 @@ const Foo = bar({
UNSAFE_componentWillUpdate: function() {}
});
```

## Rule Options
```json
...
"react/no-unsafe": [<enabled>, { "checkAliases": <boolean> }]
...
```

### `checkAliases` (default: `false`)

When `true` the rule will also check aliases of unsafe methods: `componentWillMount`, `componentWillReceiveProps`, `componentWillUpdate`.

The following patterns are considered warnings:

```jsx
class Foo extends React.Component {
componentWillMount() {}
componentWillReceiveProps() {}
componentWillUpdate() {}
}
```

```jsx
const Foo = createReactClass({
componentWillMount: function() {},
componentWillReceiveProps: function() {},
componentWillUpdate: function() {}
});
```

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

```jsx
class Foo extends Bar {
componentWillMount() {}
componentWillReceiveProps() {}
componentWillUpdate() {}
}
```

```jsx
const Foo = bar({
componentWillMount: function() {},
componentWillReceiveProps: function() {},
componentWillUpdate: function() {}
});
```
55 changes: 46 additions & 9 deletions lib/rules/no-unsafe.js
@@ -1,5 +1,5 @@
/**
* @fileoverview Prevent usage of UNSAFE_ methods
* @fileoverview Prevent usage of unsafe lifecycle methods
* @author Sergei Startsev
*/

Expand All @@ -17,30 +17,63 @@ const versionUtil = require('../util/version');
module.exports = {
meta: {
docs: {
description: 'Prevent usage of UNSAFE_ methods',
description: 'Prevent usage of unsafe lifecycle methods',
category: 'Best Practices',
recommended: false,
url: docsUrl('no-unsafe')
},
schema: []
schema: [
{
type: 'object',
properties: {
checkAliases: {
default: false,
type: 'boolean'
}
},
additionalProperties: false
}
]
},

create: Components.detect((context, components, utils) => {
const config = context.options[0] || {};
const checkAliases = config.checkAliases || false;

const isApplicable = versionUtil.testReactVersion(context, '16.3.0');
if (!isApplicable) {
return {};
}

const unsafe = {
UNSAFE_componentWillMount: {
newMethod: 'componentDidMount',
details:
'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.'
},
UNSAFE_componentWillReceiveProps: {
newMethod: 'getDerivedStateFromProps',
details:
'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.'
},
UNSAFE_componentWillUpdate: {
newMethod: 'componentDidUpdate',
details:
'See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html.'
}
};
if (checkAliases) {
unsafe.componentWillMount = unsafe.UNSAFE_componentWillMount;
unsafe.componentWillReceiveProps = unsafe.UNSAFE_componentWillReceiveProps;
unsafe.componentWillUpdate = unsafe.UNSAFE_componentWillUpdate;
}

/**
* Returns a list of unsafe methods
* @returns {Array} A list of unsafe methods
*/
function getUnsafeMethods() {
return [
'UNSAFE_componentWillMount',
'UNSAFE_componentWillReceiveProps',
'UNSAFE_componentWillUpdate'
];
return Object.keys(unsafe);
}

/**
Expand All @@ -63,9 +96,13 @@ module.exports = {
return;
}

const meta = unsafe[method];
const newMethod = meta.newMethod;
const details = meta.details;

context.report({
node: node,
message: `${method} is unsafe for use in async rendering, see https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html`
message: `${method} is unsafe for use in async rendering. Update the component to use ${newMethod} instead. ${details}`
});
}

Expand Down

0 comments on commit 4583342

Please sign in to comment.