Skip to content

Commit 768013e

Browse files
dejoeanljharb
authored andcommitted
Add support for React 16.3 lifecycle methods
- Add React 16.3 lifecycle methods to default config - Allow static method position to be overriden by specification - Note: this update means that a static method of the same name as a non-static method in the sort-comp will be considered an error if it is not placed in the position corresponding to its name - Add `instance-variables` to the lifecycle after the `constructor` and before `getDefaultProps` - Note: This update is not required, but is a nice to have since the default order has to be updated anyway, and current behavior forces all instance variables to come after `componentWillUnmount` by default, which is a strange ordering. - Note: The super constructor runs prior to instance variables being instantiated, so `this.props` can be referenced within an instance variable definition. However, instance variables are defined prior to the current class' constructor executing. Since it is hard to represent this flow I thought it would be better to place instance variables below the constructor so as to make it obvious that `this.props` is defined, since defining an instance variable then using it in the constructor seems like an unnecessary use case. - Add a test case for a React 16.3 class - Update documentation to reflect changes
1 parent 230b0ad commit 768013e

File tree

3 files changed

+101
-21
lines changed

3 files changed

+101
-21
lines changed

docs/rules/sort-comp.md

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Enforce component methods order (react/sort-comp)
22

3-
When creating React components it is more convenient to always follow the same organisation for method order to help you easily find lifecyle methods, event handlers, etc.
3+
When creating React components it is more convenient to always follow the same organisation for method order to help you easily find lifecycle methods, event handlers, etc.
44

55
**Fixable:** This rule is automatically fixable using the [`sort-comp` transform](https://github.com/reactjs/react-codemod/blob/master/transforms/sort-comp.js) in [react-codemod](https://www.npmjs.com/package/react-codemod).
66

@@ -9,7 +9,7 @@ When creating React components it is more convenient to always follow the same o
99
The default configuration ensures that the following order must be followed:
1010

1111
1. static methods and properties
12-
2. lifecycle methods: `displayName`, `propTypes`, `contextTypes`, `childContextTypes`, `mixins`, `statics`,`defaultProps`, `constructor`, `getDefaultProps`, `getInitialState`, `state`, `getChildContext`, `componentWillMount`, `componentDidMount`, `componentWillReceiveProps`, `shouldComponentUpdate`, `componentWillUpdate`, `componentDidUpdate`, `componentWillUnmount` (in this order).
12+
2. lifecycle methods: `displayName`, `propTypes`, `contextTypes`, `childContextTypes`, `mixins`, `statics`, `defaultProps`, `constructor`, `getDefaultProps`, `state`, `getInitialState`, `getChildContext`, `getDerivedStateFromProps`, `componentWillMount`, `UNSAFE_componentWillMount`, `componentDidMount`, `componentWillReceiveProps`, `UNSAFE_componentWillReceiveProps`, `shouldComponentUpdate`, `componentWillUpdate`, `UNSAFE_componentWillUpdate`, `getSnapshotBeforeUpdate`, `componentDidUpdate`, `componentDidCatch`, `componentWillUnmount` (in this order).
1313
3. custom methods
1414
4. `render` method
1515

@@ -70,30 +70,36 @@ The default configuration is:
7070
'defaultProps',
7171
'constructor',
7272
'getDefaultProps',
73-
'getInitialState',
7473
'state',
74+
'getInitialState',
7575
'getChildContext',
76+
'getDerivedStateFromProps',
7677
'componentWillMount',
78+
'UNSAFE_componentWillMount',
7779
'componentDidMount',
7880
'componentWillReceiveProps',
81+
'UNSAFE_componentWillReceiveProps',
7982
'shouldComponentUpdate',
8083
'componentWillUpdate',
84+
'UNSAFE_componentWillUpdate',
85+
'getSnapshotBeforeUpdate',
8186
'componentDidUpdate',
87+
'componentDidCatch',
8288
'componentWillUnmount'
8389
]
8490
}
8591
}
8692
```
8793

8894
* `static-methods` is a special keyword that refers to static class methods.
89-
* `lifecycle` is referring to the `lifecycle` group defined in `groups`.
90-
* `everything-else` is a special group that match all the methods that do not match any of the other groups.
91-
* `render` is referring to the `render` method.
92-
* `type-annotations`. This group is not specified by default, but can be used to enforce flow annotations positioning.
93-
* `getters` This group is not specified by default, but can be used to enforce class getters positioning.
94-
* `setters` This group is not specified by default, but can be used to enforce class setters positioning.
95-
* `instance-variables` This group is not specified by default, but can be used to enforce all other instance variables positioning.
96-
* `instance-methods` This group is not specified by default, but can be used to enforce all other instance methods positioning.
95+
* `lifecycle` refers to the `lifecycle` group defined in `groups`.
96+
* `everything-else` is a special group that matches all of the methods that do not match any of the other groups.
97+
* `render` refers to the `render` method.
98+
* `type-annotations`. This group is not specified by default, but can be used to enforce flow annotations' positioning.
99+
* `getters` This group is not specified by default, but can be used to enforce class getters' positioning.
100+
* `setters` This group is not specified by default, but can be used to enforce class setters' positioning.
101+
* `instance-variables` This group is not specified by default, but can be used to enforce all other instance variables' positioning.
102+
* `instance-methods` This group is not specified by default, but can be used to enforce all other instance methods' positioning.
97103

98104
You can override this configuration to match your needs.
99105

@@ -217,7 +223,6 @@ class Hello extends React.Component<any, Props, void> {
217223
}
218224
```
219225

220-
221226
## When Not To Use It
222227

223228
This rule is a formatting preference and not following it won't negatively affect the quality of your code. If components organisation isn't a part of your coding standards, then you can leave this rule off.

lib/rules/sort-comp.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@ const defaultConfig = {
3232
'state',
3333
'getInitialState',
3434
'getChildContext',
35+
'getDerivedStateFromProps',
3536
'componentWillMount',
37+
'UNSAFE_componentWillMount',
3638
'componentDidMount',
3739
'componentWillReceiveProps',
40+
'UNSAFE_componentWillReceiveProps',
3841
'shouldComponentUpdate',
3942
'componentWillUpdate',
43+
'UNSAFE_componentWillUpdate',
44+
'getSnapshotBeforeUpdate',
4045
'componentDidUpdate',
46+
'componentDidCatch',
4147
'componentWillUnmount'
4248
]
4349
}
@@ -131,13 +137,6 @@ module.exports = {
131137
let j;
132138
const indexes = [];
133139

134-
if (method.static) {
135-
const staticIndex = methodsOrder.indexOf('static-methods');
136-
if (staticIndex >= 0) {
137-
indexes.push(staticIndex);
138-
}
139-
}
140-
141140
if (method.getter) {
142141
const getterIndex = methodsOrder.indexOf('getters');
143142
if (getterIndex >= 0) {
@@ -159,8 +158,6 @@ module.exports = {
159158
}
160159
}
161160

162-
// Either this is not a static method or static methods are not specified
163-
// in the methodsOrder.
164161
if (indexes.length === 0) {
165162
for (i = 0, j = methodsOrder.length; i < j; i++) {
166163
isRegExp = methodsOrder[i].match(regExpRegExp);
@@ -175,6 +172,13 @@ module.exports = {
175172
}
176173
}
177174

175+
if (method.static) {
176+
const staticIndex = methodsOrder.indexOf('static-methods');
177+
if (staticIndex >= 0) {
178+
indexes.push(staticIndex);
179+
}
180+
}
181+
178182
if (indexes.length === 0 && method.instanceVariable) {
179183
const annotationIndex = methodsOrder.indexOf('instance-variables');
180184
if (annotationIndex >= 0) {

tests/lib/rules/sort-comp.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,77 @@ ruleTester.run('sort-comp', rule, {
9191
'everything-else'
9292
]
9393
}]
94+
}, {
95+
// Must validate a full React 16.3 createReactClass class
96+
code: [
97+
'var Hello = createReactClass({',
98+
' displayName : \'\',',
99+
' propTypes: {},',
100+
' contextTypes: {},',
101+
' childContextTypes: {},',
102+
' mixins: [],',
103+
' statics: {},',
104+
' getDefaultProps: function() {},',
105+
' getInitialState: function() {},',
106+
' getChildContext: function() {},',
107+
' UNSAFE_componentWillMount: function() {},',
108+
' componentDidMount: function() {},',
109+
' UNSAFE_componentWillReceiveProps: function() {},',
110+
' shouldComponentUpdate: function() {},',
111+
' UNSAFE_componentWillUpdate: function() {},',
112+
' getSnapshotBeforeUpdate: function() {},',
113+
' componentDidUpdate: function() {},',
114+
' componentDidCatch: function() {},',
115+
' componentWillUnmount: function() {},',
116+
' render: function() {',
117+
' return <div>Hello</div>;',
118+
' }',
119+
'});'
120+
].join('\n')
121+
}, {
122+
// Must validate React 16.3 lifecycle methods with the default parser
123+
code: [
124+
'class Hello extends React.Component {',
125+
' constructor() {}',
126+
' static getDerivedStateFromProps() {}',
127+
' UNSAFE_componentWillMount() {}',
128+
' componentDidMount() {}',
129+
' UNSAFE_componentWillReceiveProps() {}',
130+
' shouldComponentUpdate() {}',
131+
' UNSAFE_componentWillUpdate() {}',
132+
' getSnapshotBeforeUpdate() {}',
133+
' componentDidUpdate() {}',
134+
' componentDidCatch() {}',
135+
' componentWillUnmount() {}',
136+
' testInstanceMethod() {}',
137+
' render() { return (<div>Hello</div>); }',
138+
'}'
139+
].join('\n')
140+
}, {
141+
// Must validate a full React 16.3 ES6 class
142+
code: [
143+
'class Hello extends React.Component {',
144+
' static displayName = \'\'',
145+
' static propTypes = {}',
146+
' static defaultProps = {}',
147+
' constructor() {}',
148+
' state = {}',
149+
' static getDerivedStateFromProps = () => {}',
150+
' UNSAFE_componentWillMount = () => {}',
151+
' componentDidMount = () => {}',
152+
' UNSAFE_componentWillReceiveProps = () => {}',
153+
' shouldComponentUpdate = () => {}',
154+
' UNSAFE_componentWillUpdate = () => {}',
155+
' getSnapshotBeforeUpdate = () => {}',
156+
' componentDidUpdate = () => {}',
157+
' componentDidCatch = () => {}',
158+
' componentWillUnmount = () => {}',
159+
' testArrowMethod = () => {}',
160+
' testInstanceMethod() {}',
161+
' render = () => (<div>Hello</div>)',
162+
'}'
163+
].join('\n'),
164+
parser: 'babel-eslint'
94165
}, {
95166
// Must allow us to create a RegExp-based group
96167
code: [

0 commit comments

Comments
 (0)