Skip to content

Commit

Permalink
[New] add no-arrow-function-lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
ngtan authored and ljharb committed Sep 13, 2018
1 parent d3b5d71 commit 74f99be
Show file tree
Hide file tree
Showing 8 changed files with 855 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2754,3 +2754,4 @@ If you're still not using React 15 you can keep the old behavior by setting the
[`static-property-placement`]: docs/rules/static-property-placement.md
[`jsx-curly-newline`]: docs/rules/jsx-curly-newline.md
[`jsx-no-useless-fragment`]: docs/rules/jsx-no-useless-fragment.md
[`no-arrow-function-lifecycle`]: docs/rules/no-arrow-function-lifecycle.md
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -109,6 +109,7 @@ Enable the rules that you would like to use.
* [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md): Forbid foreign propTypes
* [react/no-access-state-in-setstate](docs/rules/no-access-state-in-setstate.md): Prevent using this.state inside this.setState
* [react/no-array-index-key](docs/rules/no-array-index-key.md): Prevent using Array index in `key` props
* [react/no-arrow-function-lifecycle](docs/rules/no-arrow-function-lifecycle.md): Don't use arrow function for lifecycle methods
* [react/no-children-prop](docs/rules/no-children-prop.md): Prevent passing children as props
* [react/no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
* [react/no-danger-with-children](docs/rules/no-danger-with-children.md): Prevent problem with children and props.dangerouslySetInnerHTML
Expand Down
41 changes: 41 additions & 0 deletions docs/rules/no-arrow-function-lifecycle.md
@@ -0,0 +1,41 @@
# Lifecycle methods should be methods on the prototype, not class fields (react/no-arrow-function-lifecycle)

It is not neccessary to use arrow function for lifecycle methods. This makes things harder to test, conceptually less performant (although in practice, performance will not be affected, since most engines will optimize efficiently), and can break hot reloading patterns.

## Rule Details

The following patterns are considered warnings:

```jsx
class Hello extends React.Component {
render = () => {
return <div />;
}
}

var AnotherHello = createReactClass({
render: () => {
return <div />;
},
});
```

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

```jsx
class Hello extends React.Component {
render() {
return <div />;
}
}

var AnotherHello = createReactClass({
render() {
return <div />;
},
});

```
## When Not To Use It

If you don't care about performance of your application or conceptual correctness of class property placement, you can disable this rule.
1 change: 1 addition & 0 deletions index.js
Expand Up @@ -52,6 +52,7 @@ const allRules = {
'jsx-wrap-multilines': require('./lib/rules/jsx-wrap-multilines'),
'no-access-state-in-setstate': require('./lib/rules/no-access-state-in-setstate'),
'no-array-index-key': require('./lib/rules/no-array-index-key'),
'no-arrow-function-lifecycle': require('./lib/rules/no-arrow-function-lifecycle'),
'no-children-prop': require('./lib/rules/no-children-prop'),
'no-danger': require('./lib/rules/no-danger'),
'no-danger-with-children': require('./lib/rules/no-danger-with-children'),
Expand Down
55 changes: 55 additions & 0 deletions lib/rules/no-arrow-function-lifecycle.js
@@ -0,0 +1,55 @@
/**
* @fileoverview Lifecycle methods should be methods on the prototype, not class fields
* @author Tan Nguyen
*/
'use strict';

const Components = require('../util/Components');
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const lifecycleMethods = require('../util/lifecycleMethods');

module.exports = {
meta: {
docs: {
description: 'Lifecycle methods should be methods on the prototype, not class fields',
category: 'Best Practices',
recommended: false,
url: docsUrl('no-arrow-function-lifecycle')
},
schema: []
},

create: Components.detect((context, components) => {
/**
* @param {Array} properties list of component properties
*/
function reportNoArrowFunctionLifecycle(properties) {
properties.forEach(node => {
const propertyName = astUtil.getPropertyName(node);
const nodeType = node.value && node.value.type;
const isLifecycleMethod = lifecycleMethods.indexOf(propertyName) !== -1;

if (nodeType === 'ArrowFunctionExpression' && isLifecycleMethod) {
context.report({
node,
message: '{{propertyName}} is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.',
data: {
propertyName
}
});
}
});
}

return {
'Program:exit': function() {
const list = components.list();
Object.keys(list).forEach(component => {
const properties = astUtil.getComponentProperties(list[component].node);
reportNoArrowFunctionLifecycle(properties);
});
}
};
})
};
19 changes: 2 additions & 17 deletions lib/rules/no-typos.js
Expand Up @@ -7,28 +7,13 @@
const PROP_TYPES = Object.keys(require('prop-types'));
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const lifecycleMethods = require('../util/lifecycleMethods');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

const STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps'];
const LIFECYCLE_METHODS = [
'getDerivedStateFromProps',
'componentWillMount',
'UNSAFE_componentWillMount',
'componentDidMount',
'componentWillReceiveProps',
'UNSAFE_componentWillReceiveProps',
'shouldComponentUpdate',
'componentWillUpdate',
'UNSAFE_componentWillUpdate',
'getSnapshotBeforeUpdate',
'componentDidUpdate',
'componentDidCatch',
'componentWillUnmount',
'render'
];

module.exports = {
meta: {
Expand Down Expand Up @@ -143,7 +128,7 @@ module.exports = {
}

function reportErrorIfLifecycleMethodCasingTypo(node) {
LIFECYCLE_METHODS.forEach((method) => {
lifecycleMethods.forEach(method => {
if (method.toLowerCase() === node.key.name.toLowerCase() && method !== node.key.name) {
context.report({
node,
Expand Down
25 changes: 25 additions & 0 deletions lib/util/lifecycleMethods.js
@@ -0,0 +1,25 @@
/**
* @fileoverview lifecycle methods
* @author Tan Nguyen
*/
'use strict';

module.exports = [
'getDefaultProps',
'getInitialState',
'getChildContext',
'getDerivedStateFromProps',
'componentWillMount',
'UNSAFE_componentWillMount',
'componentDidMount',
'componentWillReceiveProps',
'UNSAFE_componentWillReceiveProps',
'shouldComponentUpdate',
'componentWillUpdate',
'UNSAFE_componentWillUpdate',
'getSnapshotBeforeUpdate',
'componentDidUpdate',
'componentDidCatch',
'componentWillUnmount',
'render'
];

0 comments on commit 74f99be

Please sign in to comment.