diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js index 84bbf6c162..4134ed5e11 100644 --- a/packages/eslint-config-airbnb/rules/react.js +++ b/packages/eslint-config-airbnb/rules/react.js @@ -244,6 +244,7 @@ module.exports = { 'static-methods', 'instance-variables', 'lifecycle', + '/^handle.+$/', '/^on.+$/', 'getters', 'setters', diff --git a/packages/eslint-config-airbnb/test/test-react-order.js b/packages/eslint-config-airbnb/test/test-react-order.js index d45cac8ae1..a394fe1c3c 100644 --- a/packages/eslint-config-airbnb/test/test-react-order.js +++ b/packages/eslint-config-airbnb/test/test-react-order.js @@ -33,7 +33,7 @@ ${body}} `; } -test('validate react prop order', (t) => { +test('validate react methods order', (t) => { t.test('make sure our eslintrc has React and JSX linting dependencies', (t) => { t.plan(2); t.deepEqual(reactRules.plugins, ['react']); @@ -44,6 +44,8 @@ test('validate react prop order', (t) => { t.plan(3); const result = lint(wrapComponent(` componentDidMount() {} + handleSubmit() {} + onButtonAClick() {} setFoo() {} getFoo() {} setBar() {} @@ -88,4 +90,47 @@ test('validate react prop order', (t) => { t.ok(result.errorCount, 'fails'); t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort'); }); + + t.test('order: when handler method with `handle` prefix after method with `on` prefix', (t) => { + t.plan(2); + const result = lint(wrapComponent(` + componentDidMount() {} + onButtonAClick() {} + handleSubmit() {} + setFoo() {} + getFoo() {} + render() { return
; } +`)); + + t.ok(result.errorCount, 'fails'); + t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort'); + }); + + t.test('order: when lifecycle methods after event handler methods', (t) => { + t.plan(2); + const result = lint(wrapComponent(` + handleSubmit() {} + componentDidMount() {} + setFoo() {} + getFoo() {} + render() { return
; } +`)); + + t.ok(result.errorCount, 'fails'); + t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort'); + }); + + t.test('order: when event handler methods after getters and setters', (t) => { + t.plan(2); + const result = lint(wrapComponent(` + componentDidMount() {} + setFoo() {} + getFoo() {} + handleSubmit() {} + render() { return
; } +`)); + + t.ok(result.errorCount, 'fails'); + t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort'); + }); }); diff --git a/react/README.md b/react/README.md index 4811ddaf70..e7679d26da 100644 --- a/react/README.md +++ b/react/README.md @@ -667,7 +667,8 @@ We don’t recommend using indexes for keys if the order of items may change. 1. `componentWillUpdate` 1. `componentDidUpdate` 1. `componentWillUnmount` - 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()` + 1. *event handlers starting with 'handle'* like `handleSubmit()` or `handleChangeDescription()` + 1. *event handlers starting with 'on'* like `onClickSubmit()` or `onChangeDescription()` 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()` 1. *optional render methods* like `renderNavigation()` or `renderProfilePicture()` 1. `render`