diff --git a/docs/rules/destructuring-assignment.md b/docs/rules/destructuring-assignment.md index 0f8ed6ee4c..f4b6e2ccde 100644 --- a/docs/rules/destructuring-assignment.md +++ b/docs/rules/destructuring-assignment.md @@ -96,7 +96,7 @@ const Foo = class extends React.PureComponent { ```js ... -"react/destructuring-assignment": [, "always", { "ignoreClassFields": , "destructureInSignature": "always" | "ignore" }] +"react/destructuring-assignment": [, "always", { "ignoreClassFields": , "destructureInSignature": "always" | "ignore", "ignoreUseContext": }] ... ``` @@ -139,3 +139,18 @@ function Foo(props) { return } ``` + +### `ignoreUseContext` + +When configured with `true`, the rule will ignore values returned from `useContext`. + +Examples of **correct** code for this rule: + +```jsx +import { useContext } from 'react'; + +function Foo() { + const foo = useContext(fooContext); + return <>{foo.bar} +} +``` diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 730828619e..fbe70ba84c 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -84,6 +84,9 @@ module.exports = { 'ignore', ], }, + ignoreUseContext: { + type: 'boolean', + }, }, additionalProperties: false, }], @@ -92,6 +95,7 @@ module.exports = { create: Components.detect((context, components, utils) => { const configuration = context.options[0] || DEFAULT_OPTION; const ignoreClassFields = (context.options[1] && (context.options[1].ignoreClassFields === true)) || false; + const ignoreUseContext = (context.options[1] && (context.options[1].ignoreUseContext === true)) || false; const destructureInSignature = (context.options[1] && context.options[1].destructureInSignature) || 'ignore'; const sfcParams = createSFCParams(); @@ -152,7 +156,7 @@ module.exports = { const optional = node.optional // the below is for the old typescript-eslint parser || context.getSourceCode().getText(node).slice(node.object.range[1] - node.range[0], node.object.range[1] - node.range[0] + 1) === '?'; - if (isContextUsed && configuration === 'always' && !optional) { + if (isContextUsed && configuration === 'always' && !ignoreUseContext && !optional) { report(context, messages.useDestructAssignment, 'useDestructAssignment', { node, data: { @@ -247,7 +251,7 @@ module.exports = { contextSet.add(node.id.name); } - if (SFCComponent && destructuringUseContext && configuration === 'never') { + if (SFCComponent && destructuringUseContext && !ignoreUseContext && configuration === 'never') { report(context, messages.noDestructAssignment, 'noDestructAssignment', { node, data: { diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index b578fd0293..023efac8eb 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -433,6 +433,30 @@ ruleTester.run('destructuring-assignment', rule, { `, features: ['optional chaining'], }, + { + code: ` + import { useContext } from 'react'; + + const MyComponent = (props) => { + const foo = useContext(aContext); + return
{foo.test}
+ }; + `, + options: ['always', { ignoreUseContext: true }], + settings: { react: { version: '16.9.0' } }, + }, + { + code: ` + import { useContext } from 'react'; + + const MyComponent = (props) => { + const {foo} = useContext(aContext); + return
{foo}
+ }; + `, + options: ['never', { ignoreUseContext: true }], + settings: { react: { version: '16.9.0' } }, + }, ]), invalid: parsers.all([].concat( @@ -890,6 +914,36 @@ ruleTester.run('destructuring-assignment', rule, { errors: [ { message: 'Must never use destructuring useContext assignment' }, ], + }, + { + code: ` + import { useContext } from 'react'; + + const MyComponent = (props) => { + const foo = useContext(aContext); + return
{foo.test}
+ }; + `, + options: ['always', { ignoreUseContext: false }], + settings: { react: { version: '16.9.0' } }, + errors: [ + { message: 'Must use destructuring foo assignment' }, + ], + }, + { + code: ` + import { useContext } from 'react'; + + const MyComponent = (props) => { + const {foo} = useContext(aContext); + return
{foo}
+ }; + `, + options: ['never', { ignoreUseContext: false }], + settings: { react: { version: '16.9.0' } }, + errors: [ + { message: 'Must never use destructuring useContext assignment' }, + ], } )), });