Skip to content

Commit 14451d4

Browse files
authored
Merge pull request #2085 from himynameisdave/issues/2083
Fix: no-array-index-key not working in React.Children methods
2 parents 77e3fd0 + 8be52c7 commit 14451d4

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

docs/rules/no-array-index-key.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ things.reduce((collection, thing, index) => (
5050
things.reduceRight((collection, thing, index) => (
5151
collection.concat(<Hello key={index} />)
5252
), []);
53+
54+
React.Children.map(this.props.children, (child, index) => (
55+
React.cloneElement(child, { key: index })
56+
))
57+
58+
Children.forEach(this.props.children, (child, index) => (
59+
React.cloneElement(child, { key: index })
60+
))
5361
```
5462

5563
The following patterns are **not** considered warnings:

lib/rules/no-array-index-key.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
const has = require('has');
88
const astUtil = require('../util/ast');
99
const docsUrl = require('../util/docsUrl');
10+
const pragma = require('../util/pragma');
1011

1112
// ------------------------------------------------------------------------------
1213
// Rule Definition
@@ -47,6 +48,32 @@ module.exports = {
4748
&& indexParamNames.indexOf(node.name) !== -1;
4849
}
4950

51+
function isUsingReactChildren(node) {
52+
const callee = node.callee;
53+
if (
54+
!callee
55+
|| !callee.property
56+
|| !callee.object
57+
) {
58+
return null;
59+
}
60+
61+
const isReactChildMethod = ['map', 'forEach'].indexOf(callee.property.name) > -1;
62+
if (!isReactChildMethod) {
63+
return null;
64+
}
65+
66+
const obj = callee.object;
67+
if (obj && obj.name === 'Children') {
68+
return true;
69+
}
70+
if (obj && obj.object && obj.object.name === pragma.getFromContext(context)) {
71+
return true;
72+
}
73+
74+
return false;
75+
}
76+
5077
function getMapIndexParamName(node) {
5178
const callee = node.callee;
5279
if (callee.type !== 'MemberExpression') {
@@ -59,16 +86,19 @@ module.exports = {
5986
return null;
6087
}
6188

62-
const firstArg = node.arguments[0];
63-
if (!firstArg) {
89+
const callbackArg = isUsingReactChildren(node)
90+
? node.arguments[1]
91+
: node.arguments[0];
92+
93+
if (!callbackArg) {
6494
return null;
6595
}
6696

67-
if (!astUtil.isFunctionLikeExpression(firstArg)) {
97+
if (!astUtil.isFunctionLikeExpression(callbackArg)) {
6898
return null;
6999
}
70100

71-
const params = firstArg.params;
101+
const params = callbackArg.params;
72102

73103
const indexParamPosition = iteratorFunctionsToIndexParamPosition[callee.property.name];
74104
if (params.length < indexParamPosition + 1) {

tests/lib/rules/no-array-index-key.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@ ruleTester.run('no-array-index-key', rule, {
8989

9090
{
9191
code: 'foo.reduceRight((a, b, i) => a.concat(<Foo key={b.id} />), [])'
92+
},
93+
94+
{
95+
code: `
96+
React.Children.map(this.props.children, (child, index, arr) => {
97+
return React.cloneElement(child, { key: child.id });
98+
})
99+
`
100+
},
101+
102+
{
103+
code: `
104+
Children.forEach(this.props.children, (child, index, arr) => {
105+
return React.cloneElement(child, { key: child.id });
106+
})
107+
`
92108
}
93109
],
94110

@@ -227,6 +243,43 @@ ruleTester.run('no-array-index-key', rule, {
227243
{
228244
code: 'foo.findIndex((bar, i) => { baz.push(React.createElement(\'Foo\', { key: i })); })',
229245
errors: [{message: 'Do not use Array index in keys'}]
246+
},
247+
248+
{
249+
code: `
250+
Children.map(this.props.children, (child, index) => {
251+
return React.cloneElement(child, { key: index });
252+
})
253+
`,
254+
errors: [{message: 'Do not use Array index in keys'}]
255+
},
256+
257+
{
258+
code: `
259+
React.Children.map(this.props.children, (child, index) => {
260+
return React.cloneElement(child, { key: index });
261+
})
262+
`,
263+
errors: [{message: 'Do not use Array index in keys'}]
264+
},
265+
266+
{
267+
code: `
268+
Children.forEach(this.props.children, (child, index) => {
269+
return React.cloneElement(child, { key: index });
270+
})
271+
`,
272+
errors: [{message: 'Do not use Array index in keys'}]
273+
},
274+
275+
{
276+
code: `
277+
React.Children.forEach(this.props.children, (child, index) => {
278+
return React.cloneElement(child, { key: index });
279+
})
280+
`,
281+
errors: [{message: 'Do not use Array index in keys'}]
230282
}
283+
231284
]
232285
});

0 commit comments

Comments
 (0)