Skip to content

Commit e7704e2

Browse files
authored
[babel-plugin-react-jsx] Avoid duplicate "children" key in props object (#17094)
* [babel-plugin-react-jsx] Avoid duplicate "children" key in props object * Use Object.assign approach
1 parent fdba0e5 commit e7704e2

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,4 +480,10 @@ describe('transform react to jsx', () => {
480480
transform(`<Component y={2} {...x} />`, {useBuiltIns: false})
481481
).toMatchSnapshot();
482482
});
483+
484+
it('should not contain duplicate children key in props object', () => {
485+
expect(
486+
transform(`<Component children={1}>2</Component>`)
487+
).toMatchSnapshot();
488+
});
483489
});

packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,14 @@ var e = React.jsx(F, {
250250
});
251251
`;
252252

253+
exports[`transform react to jsx should not contain duplicate children key in props object 1`] = `
254+
React.jsx(Component, Object.assign({
255+
children: 1
256+
}, {
257+
children: "2"
258+
}));
259+
`;
260+
253261
exports[`transform react to jsx should not strip nbsp even couple with other whitespace 1`] = `
254262
React.jsx("div", {
255263
children: "\\xA0 "

packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,20 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
268268
);
269269
}
270270

271+
function isChildrenProp(prop) {
272+
return (
273+
t.isJSXAttribute(prop) &&
274+
t.isJSXIdentifier(prop.name) &&
275+
prop.name.name === 'children'
276+
);
277+
}
278+
271279
// Builds props for React.jsx. This function adds children into the props
272280
// and ensures that props is always an object
273281
function buildJSXOpeningElementAttributes(attribs, file, children) {
274282
let _props = [];
275283
const objs = [];
284+
const hasChildren = children && children.length > 0;
276285

277286
const useBuiltIns = file.opts.useBuiltIns || false;
278287
if (typeof useBuiltIns !== 'boolean') {
@@ -287,14 +296,22 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
287296
if (t.isJSXSpreadAttribute(prop)) {
288297
_props = pushProps(_props, objs);
289298
objs.push(prop.argument);
299+
} else if (hasChildren && isChildrenProp(prop)) {
300+
// In order to avoid having duplicate "children" keys, we avoid
301+
// pushing the "children" prop if we have actual children. Instead
302+
// we put the children into a separate object and then rely on
303+
// the Object.assign logic below to ensure the correct object is
304+
// formed.
305+
_props = pushProps(_props, objs);
306+
objs.push(t.objectExpression([convertAttribute(prop)]));
290307
} else {
291308
_props.push(convertAttribute(prop));
292309
}
293310
}
294311

295312
// In React.JSX, children is no longer a separate argument, but passed in
296313
// through the argument object
297-
if (children && children.length > 0) {
314+
if (hasChildren) {
298315
if (children.length === 1) {
299316
_props.push(t.objectProperty(t.identifier('children'), children[0]));
300317
} else {

0 commit comments

Comments
 (0)