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 committed Sep 19, 2021
1 parent 227e967 commit 9bea9cd
Show file tree
Hide file tree
Showing 8 changed files with 919 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -3457,6 +3457,12 @@ If you're still not using React 15 you can keep the old behavior by setting the
[`sort-prop-types`]: docs/rules/sort-prop-types.md
[`state-in-constructor`]: docs/rules/state-in-constructor.md
[`static-property-placement`]: docs/rules/static-property-placement.md
<<<<<<< HEAD
[`style-prop-object`]: docs/rules/style-prop-object.md
[`void-dom-elements-no-children`]: docs/rules/void-dom-elements-no-children.md
[`wrap-multilines`]: docs/rules/jsx-wrap-multilines.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
>>>>>>> [New] add `no-arrow-function-lifecycle`
53 changes: 53 additions & 0 deletions README.md
Expand Up @@ -115,6 +115,7 @@ Enable the rules that you would like to use.

# List of supported rules

<<<<<<< HEAD
✔: Enabled in the [`recommended`](#recommended) configuration.\
🔧: Fixable with [`eslint --fix`](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems).

Expand Down Expand Up @@ -175,6 +176,58 @@ Enable the rules that you would like to use.
| | | [react/style-prop-object](docs/rules/style-prop-object.md) | Enforce style prop value is an object |
| | | [react/void-dom-elements-no-children](docs/rules/void-dom-elements-no-children.md) | Prevent passing of children to void DOM elements (e.g. `<br />`). |
<!-- AUTO-GENERATED-CONTENT:END -->
=======
* [react/boolean-prop-naming](docs/rules/boolean-prop-naming.md): Enforces consistent naming for boolean props
* [react/button-has-type](docs/rules/button-has-type.md): Forbid "button" element without an explicit "type" attribute
* [react/default-props-match-prop-types](docs/rules/default-props-match-prop-types.md): Prevent extraneous defaultProps on components
* [react/destructuring-assignment](docs/rules/destructuring-assignment.md): Rule enforces consistent usage of destructuring assignment in component
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
* [react/forbid-dom-props](docs/rules/forbid-dom-props.md): Forbid certain props on DOM Nodes
* [react/forbid-elements](docs/rules/forbid-elements.md): Forbid certain elements
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
* [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
* [react/no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods, including component lifecycle methods
* [react/no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of `setState` in `componentDidMount`
* [react/no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of `setState` in `componentDidUpdate`
* [react/no-direct-mutation-state](docs/rules/no-direct-mutation-state.md): Prevent direct mutation of `this.state`
* [react/no-find-dom-node](docs/rules/no-find-dom-node.md): Prevent usage of `findDOMNode`
* [react/no-is-mounted](docs/rules/no-is-mounted.md): Prevent usage of `isMounted`
* [react/no-multi-comp](docs/rules/no-multi-comp.md): Prevent multiple component definition per file
* [react/no-redundant-should-component-update](docs/rules/no-redundant-should-component-update.md): Prevent usage of `shouldComponentUpdate` when extending React.PureComponent
* [react/no-render-return-value](docs/rules/no-render-return-value.md): Prevent usage of the return value of `React.render`
* [react/no-set-state](docs/rules/no-set-state.md): Prevent usage of `setState`
* [react/no-typos](docs/rules/no-typos.md): Prevent common casing typos
* [react/no-string-refs](docs/rules/no-string-refs.md): Prevent using string references in `ref` attribute.
* [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 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`
* [react/prefer-es6-class](docs/rules/prefer-es6-class.md): Enforce ES5 or ES6 class for React Components
* [react/prefer-read-only-props](docs/rules/prefer-read-only-props.md): Enforce that props are read-only
* [react/prefer-stateless-function](docs/rules/prefer-stateless-function.md): Enforce stateless React Components to be written as a pure function
* [react/prop-types](docs/rules/prop-types.md): Prevent missing props validation in a React component definition
* [react/react-in-jsx-scope](docs/rules/react-in-jsx-scope.md): Prevent missing `React` when using JSX
* [react/require-default-props](docs/rules/require-default-props.md): Enforce a defaultProps definition for every prop that is not a required prop
* [react/require-optimization](docs/rules/require-optimization.md): Enforce React components to have a `shouldComponentUpdate` method
* [react/require-render-return](docs/rules/require-render-return.md): Enforce ES5 or ES6 class for returning value in render function
* [react/self-closing-comp](docs/rules/self-closing-comp.md): Prevent extra closing tags for components without children (fixable)
* [react/sort-comp](docs/rules/sort-comp.md): Enforce component methods order (fixable)
* [react/sort-prop-types](docs/rules/sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
* [react/state-in-constructor](docs/rules/state-in-constructor.md): Enforce the state initialization style to be either in a constructor or with a class property
* [react/static-property-placement](docs/rules/static-property-placement.md): Enforces where React component static properties should be positioned.
* [react/style-prop-object](docs/rules/style-prop-object.md): Enforce style prop value being an object
* [react/void-dom-elements-no-children](docs/rules/void-dom-elements-no-children.md): Prevent void DOM elements (e.g. `<img />`, `<br />`) from receiving children
>>>>>>> [New] add `no-arrow-function-lifecycle`
## JSX-specific rules

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 @@ -57,6 +57,7 @@ const allRules = {
'no-access-state-in-setstate': require('./lib/rules/no-access-state-in-setstate'),
'no-adjacent-inline-elements': require('./lib/rules/no-adjacent-inline-elements'),
'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);
});
}
};
})
};
9 changes: 9 additions & 0 deletions lib/rules/no-typos.js
Expand Up @@ -7,12 +7,14 @@
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'];
<<<<<<< HEAD
const STATIC_LIFECYCLE_METHODS = ['getDerivedStateFromProps'];
const LIFECYCLE_METHODS = [
'getDerivedStateFromProps',
Expand All @@ -30,6 +32,8 @@ const LIFECYCLE_METHODS = [
'componentWillUnmount',
'render'
];
=======
>>>>>>> [New] add `no-arrow-function-lifecycle`
module.exports = {
meta: {
Expand Down Expand Up @@ -157,6 +161,7 @@ module.exports = {
}

function reportErrorIfLifecycleMethodCasingTypo(node) {
<<<<<<< HEAD
const key = node.key;
let nodeKeyName = key.name;
if (key.type === 'Literal') {
Expand All @@ -180,6 +185,10 @@ module.exports = {
LIFECYCLE_METHODS.forEach((method) => {
if (method.toLowerCase() === nodeKeyName.toLowerCase() && method !== nodeKeyName) {
=======
lifecycleMethods.forEach(method => {
if (method.toLowerCase() === node.key.name.toLowerCase() && method !== node.key.name) {
>>>>>>> [New] add `no-arrow-function-lifecycle`
context.report({
node,
messageId: 'typoLifecycleMethod',
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 9bea9cd

Please sign in to comment.