diff --git a/packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js b/packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js
index 86ee84f1fa260..ce8403941725b 100644
--- a/packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js
+++ b/packages/babel-plugin-react-jsx/__tests__/TransformJSXToReactJSX-test.js
@@ -480,4 +480,10 @@ describe('transform react to jsx', () => {
transform(``, {useBuiltIns: false})
).toMatchSnapshot();
});
+
+ it('should not contain duplicate children key in props object', () => {
+ expect(
+ transform(`2`)
+ ).toMatchSnapshot();
+ });
});
diff --git a/packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap b/packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap
index e5b844b12fc0d..a335ef3806b04 100644
--- a/packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap
+++ b/packages/babel-plugin-react-jsx/__tests__/__snapshots__/TransformJSXToReactJSX-test.js.snap
@@ -250,6 +250,14 @@ var e = React.jsx(F, {
});
`;
+exports[`transform react to jsx should not contain duplicate children key in props object 1`] = `
+React.jsx(Component, Object.assign({
+ children: 1
+}, {
+ children: "2"
+}));
+`;
+
exports[`transform react to jsx should not strip nbsp even couple with other whitespace 1`] = `
React.jsx("div", {
children: "\\xA0 "
diff --git a/packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js b/packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js
index 960f75a3a8ecb..6d49d825eba25 100644
--- a/packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js
+++ b/packages/babel-plugin-react-jsx/src/TransformJSXToReactBabelPlugin.js
@@ -268,11 +268,20 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
);
}
+ function isChildrenProp(prop) {
+ return (
+ t.isJSXAttribute(prop) &&
+ t.isJSXIdentifier(prop.name) &&
+ prop.name.name === 'children'
+ );
+ }
+
// Builds props for React.jsx. This function adds children into the props
// and ensures that props is always an object
function buildJSXOpeningElementAttributes(attribs, file, children) {
let _props = [];
const objs = [];
+ const hasChildren = children && children.length > 0;
const useBuiltIns = file.opts.useBuiltIns || false;
if (typeof useBuiltIns !== 'boolean') {
@@ -287,6 +296,14 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
if (t.isJSXSpreadAttribute(prop)) {
_props = pushProps(_props, objs);
objs.push(prop.argument);
+ } else if (hasChildren && isChildrenProp(prop)) {
+ // In order to avoid having duplicate "children" keys, we avoid
+ // pushing the "children" prop if we have actual children. Instead
+ // we put the children into a separate object and then rely on
+ // the Object.assign logic below to ensure the correct object is
+ // formed.
+ _props = pushProps(_props, objs);
+ objs.push(t.objectExpression([convertAttribute(prop)]));
} else {
_props.push(convertAttribute(prop));
}
@@ -294,7 +311,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
// In React.JSX, children is no longer a separate argument, but passed in
// through the argument object
- if (children && children.length > 0) {
+ if (hasChildren) {
if (children.length === 1) {
_props.push(t.objectProperty(t.identifier('children'), children[0]));
} else {