eslint-plugin-react-hooks: allow OptionalMemberExpression in deps (#18819) (#18820)
* eslint-plugin-react-hooks: allow OptionalMemberExpression in deps (#18819) * add test case for #18819 * fix test * run prettier
Kevin Lewis committed
May 5, 2020 at 05:53 UTC
7992ca10df497002e0e91bb5bfbc9661c9c85b88
2 files changed
+39
-1
packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
+32
@@ -1755,6 +1755,38 @@ const tests = {
1755
},
1756
],
1757
},
1758
+ {
1759
+ code: normalizeIndent`
1760
+ function MyComponent({ history }) {
1761
+ useEffect(() => {
1762
+ return [
1763
+ history?.foo
1764
+ ];
1765
+ }, []);
1766
+ }
1767
+ `,
1768
+ errors: [
1769
+ {
1770
+ message:
1771
+ "React Hook useEffect has a missing dependency: 'history?.foo'. " +
1772
+ 'Either include it or remove the dependency array.',
1773
+ suggestions: [
1774
+ {
1775
+ desc: 'Update the dependencies array to be: [history?.foo]',
1776
+ output: normalizeIndent`
1777
+ function MyComponent({ history }) {
1778
+ useEffect(() => {
1779
+ return [
1780
+ history?.foo
1781
+ ];
1782
+ }, [history?.foo]);
1783
+ }
1784
+ `,
1785
+ },
1786
+ ],
1787
+ },
1788
+ ],
1789
+ },
1790
{
1791
code: normalizeIndent`
1792
function MyComponent() {
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+7
-1
@@ -1429,7 +1429,8 @@ function scanForDeclaredBareFunctions({
1429
*/
1430
function getDependency(node) {
1431
if (
1432
- node.parent.type === 'MemberExpression' &&
1432
+ (node.parent.type === 'MemberExpression' ||
1433
+ node.parent.type === 'OptionalMemberExpression') &&
1434
node.parent.object === node &&
1435
node.parent.property.name !== 'current' &&
1436
!node.parent.computed &&
@@ -1456,6 +1457,7 @@ function getDependency(node) {
1457
* (foo) -> 'foo'
1458
* foo.(bar) -> 'foo.bar'
1459
* foo.bar.(baz) -> 'foo.bar.baz'
1460
+ * foo?.(bar) -> 'foo?.bar'
1461
* Otherwise throw.
1462
*/
1463
function toPropertyAccessString(node) {
@@ -1465,6 +1467,10 @@ function toPropertyAccessString(node) {
1467
const object = toPropertyAccessString(node.object);
1468
const property = toPropertyAccessString(node.property);
1469
return `${object}.${property}`;
1470
+ } else if (node.type === 'OptionalMemberExpression' && !node.computed) {
1471
+ const object = toPropertyAccessString(node.object);
1472
+ const property = toPropertyAccessString(node.property);
1473
+ return `${object}?.${property}`;
1474
} else {
1475
throw new Error(`Unsupported node type: ${node.type}`);
1476
}