From 58fe0cb3557b753ff1f6ae91567527538187cc11 Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Sun, 3 Aug 2014 16:58:44 +0200 Subject: [PATCH 1/2] Don't wrap values with ReactTextComponent in traverseAllChildren Conflicts: src/utils/traverseAllChildren.js --- src/utils/flattenChildren.js | 15 ++++++++- src/utils/traverseAllChildren.js | 53 ++++++++++++++------------------ 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/utils/flattenChildren.js b/src/utils/flattenChildren.js index fe1a68cd6e0c0..6240f10aee1ec 100644 --- a/src/utils/flattenChildren.js +++ b/src/utils/flattenChildren.js @@ -18,6 +18,8 @@ "use strict"; +var ReactTextComponent = require('ReactTextComponent'); + var traverseAllChildren = require('traverseAllChildren'); var warning = require('warning'); @@ -38,7 +40,18 @@ function flattenSingleChildIntoContext(traverseContext, child, name) { name ); if (keyUnique && child != null) { - result[name] = child; + var type = typeof child; + var normalizedValue; + + if (type === 'string') { + normalizedValue = ReactTextComponent(child); + } else if (type === 'number') { + normalizedValue = ReactTextComponent('' + child); + } else { + normalizedValue = child; + } + + result[name] = normalizedValue; } } diff --git a/src/utils/traverseAllChildren.js b/src/utils/traverseAllChildren.js index 07e41b359dec7..773d570854aca 100644 --- a/src/utils/traverseAllChildren.js +++ b/src/utils/traverseAllChildren.js @@ -127,39 +127,32 @@ var traverseAllChildrenImpl = // All of the above are perceived as null. callback(traverseContext, null, storageName, indexSoFar); subtreeCount = 1; - } else if (ReactDescriptor.isValidDescriptor(children)) { + } else if (type === 'string' || type === 'number' || + ReactDescriptor.isValidDescriptor(children)) { callback(traverseContext, children, storageName, indexSoFar); subtreeCount = 1; - } else { - if (type === 'object') { - invariant( - !children || children.nodeType !== 1, - 'traverseAllChildren(...): Encountered an invalid child; DOM ' + - 'elements are not valid children of React components.' - ); - for (var key in children) { - if (children.hasOwnProperty(key)) { - subtreeCount += traverseAllChildrenImpl( - children[key], - ( - nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) + - wrapUserProvidedKey(key) + SUBSEPARATOR + - getComponentKey(children[key], 0) - ), - indexSoFar + subtreeCount, - callback, - traverseContext - ); - } + } else if (type === 'object') { + invariant( + !children || children.nodeType !== 1, + 'traverseAllChildren(...): Encountered an invalid child; DOM ' + + 'elements are not valid children of React components.' + ); + for (var key in children) { + if (children.hasOwnProperty(key)) { + var nextName = ( + nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) + + wrapUserProvidedKey(key) + SUBSEPARATOR + + getComponentKey(children[key], 0) + ); + var nextIndex = indexSoFar + subtreeCount; + subtreeCount += traverseAllChildrenImpl( + children[key], + nextName, + nextIndex, + callback, + traverseContext + ); } - } else if (type === 'string') { - var normalizedText = ReactTextComponent(children); - callback(traverseContext, normalizedText, storageName, indexSoFar); - subtreeCount += 1; - } else if (type === 'number') { - var normalizedNumber = ReactTextComponent('' + children); - callback(traverseContext, normalizedNumber, storageName, indexSoFar); - subtreeCount += 1; } } } From 9083cc3de3c1547539b3d6f9743a94c819bf9ab2 Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Mon, 4 Aug 2014 00:59:26 +0200 Subject: [PATCH 2/2] Merge adjacent ReactTextComponents in flattenChildren --- .../__tests__/ReactServerRendering-test.js | 6 +- .../__tests__/ReactMultiChildText-test.js | 80 +++++++++---------- src/utils/flattenChildren.js | 16 +++- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/browser/server/__tests__/ReactServerRendering-test.js b/src/browser/server/__tests__/ReactServerRendering-test.js index 6af97d250216b..1d1abb2970239 100644 --- a/src/browser/server/__tests__/ReactServerRendering-test.js +++ b/src/browser/server/__tests__/ReactServerRendering-test.js @@ -97,8 +97,7 @@ describe('ReactServerRendering', function() { '
' + '' + - 'My name is ' + - 'child' + + 'My name is child' + '' + '
' ); @@ -146,8 +145,7 @@ describe('ReactServerRendering', function() { expect(response).toMatch( '' + - 'Component name: ' + - 'TestComponent' + + 'Component name: TestComponent' + '' ); expect(lifecycle).toEqual( diff --git a/src/core/__tests__/ReactMultiChildText-test.js b/src/core/__tests__/ReactMultiChildText-test.js index d77c697409c2c..7099a8db68d6b 100644 --- a/src/core/__tests__/ReactMultiChildText-test.js +++ b/src/core/__tests__/ReactMultiChildText-test.js @@ -128,31 +128,31 @@ describe('ReactMultiChildText', function() { // two adjacent values [true, 0], ['0'], - [0, 0], ['0', '0'], - [1.2, 0], ['1.2', '0'], - [0, ''], ['0', ''], - ['foo', 0], ['foo', '0'], + [0, 0], ['00'], + [1.2, 0], ['1.20'], + [0, ''], ['0'], + ['foo', 0], ['foo0'], [0,
], ['0',
], [true, 1.2], ['1.2'], - [1.2, 0], ['1.2', '0'], - [1.2, 1.2], ['1.2', '1.2'], - [1.2, ''], ['1.2', ''], - ['foo', 1.2], ['foo', '1.2'], + [1.2, 0], ['1.20'], + [1.2, 1.2], ['1.21.2'], + [1.2, ''], ['1.2'], + ['foo', 1.2], ['foo1.2'], [1.2,
], ['1.2',
], [true, ''], [''], - ['', 0], ['', '0'], - [1.2, ''], ['1.2', ''], - ['', ''], ['', ''], - ['foo', ''], ['foo', ''], + ['', 0], ['0'], + [1.2, ''], ['1.2'], + ['', ''], [''], + ['foo', ''], ['foo'], ['',
], ['',
], [true, 'foo'], ['foo'], - ['foo', 0], ['foo', '0'], - [1.2, 'foo'], ['1.2', 'foo'], - ['foo', ''], ['foo', ''], - ['foo', 'foo'], ['foo', 'foo'], + ['foo', 0], ['foo0'], + [1.2, 'foo'], ['1.2foo'], + ['foo', ''], ['foo'], + ['foo', 'foo'], ['foofoo'], ['foo',
], ['foo',
], // values separated by an element @@ -161,48 +161,48 @@ describe('ReactMultiChildText', function() { ['',
, ''], ['',
, ''], ['foo',
, 'foo'], ['foo',
, 'foo'], - [true, 1.2,
, '', 'foo'], ['1.2',
, '', 'foo'], - [1.2, '',
, 'foo', true], ['1.2', '',
, 'foo'], - ['', 'foo',
, true, 1.2], ['', 'foo',
, '1.2'], + [true, 1.2,
, '', 'foo'], ['1.2',
, 'foo'], + [1.2, '',
, 'foo', true], ['1.2',
, 'foo'], + ['', 'foo',
, true, 1.2], ['foo',
, '1.2'], - [true, 1.2, '',
, 'foo', true, 1.2], ['1.2', '',
, 'foo', '1.2'], - ['', 'foo', true,
, 1.2, '', 'foo'], ['', 'foo',
, '1.2', '', 'foo'], + [true, 1.2, '',
, 'foo', true, 1.2], ['1.2',
, 'foo1.2'], + ['', 'foo', true,
, 1.2, '', 'foo'], ['foo',
, '1.2foo'], // values inside arrays [[true], [true]], [], - [[1.2], [1.2]], ['1.2', '1.2'], - [[''], ['']], ['', ''], - [['foo'], ['foo']], ['foo', 'foo'], + [[1.2], [1.2]], ['1.21.2'], + [[''], ['']], [''], + [['foo'], ['foo']], ['foofoo'], [[
], [
]], [
,
], - [[true, 1.2,
], '', 'foo'], ['1.2',
, '', 'foo'], - [1.2, '', [
, 'foo', true]], ['1.2', '',
, 'foo'], - ['', ['foo',
, true], 1.2], ['', 'foo',
, '1.2'], + [[true, 1.2,
], '', 'foo'], ['1.2',
, 'foo'], + [1.2, '', [
, 'foo', true]], ['1.2',
, 'foo'], + ['', ['foo',
, true], 1.2], ['foo',
, '1.2'], - [true, [1.2, '',
, 'foo'], true, 1.2], ['1.2', '',
, 'foo', '1.2'], - ['', 'foo', [true,
, 1.2, ''], 'foo'], ['', 'foo',
, '1.2', '', 'foo'], + [true, [1.2, '',
, 'foo'], true, 1.2], ['1.2',
, 'foo1.2'], + ['', 'foo', [true,
, 1.2, ''], 'foo'], ['foo',
, '1.2foo'], // values inside objects [{a: true}, {a: true}], [], - [{a: 1.2}, {a: 1.2}], ['1.2', '1.2'], - [{a: ''}, {a: ''}], ['', ''], - [{a: 'foo'}, {a: 'foo'}], ['foo', 'foo'], + [{a: 1.2}, {a: 1.2}], ['1.21.2'], + [{a: ''}, {a: ''}], [''], + [{a: 'foo'}, {a: 'foo'}], ['foofoo'], [{a:
}, {a:
}], [
,
], - [{a: true, b: 1.2, c:
}, '', 'foo'], ['1.2',
, '', 'foo'], - [1.2, '', {a:
, b: 'foo', c: true}], ['1.2', '',
, 'foo'], - ['', {a: 'foo', b:
, c: true}, 1.2], ['', 'foo',
, '1.2'], + [{a: true, b: 1.2, c:
}, '', 'foo'], ['1.2',
, 'foo'], + [1.2, '', {a:
, b: 'foo', c: true}], ['1.2',
, 'foo'], + ['', {a: 'foo', b:
, c: true}, 1.2], ['foo',
, '1.2'], - [true, {a: 1.2, b: '', c:
, d: 'foo'}, true, 1.2], ['1.2', '',
, 'foo', '1.2'], - ['', 'foo', {a: true, b:
, c: 1.2, d: ''}, 'foo'], ['', 'foo',
, '1.2', '', 'foo'], + [true, {a: 1.2, b: '', c:
, d: 'foo'}, true, 1.2], ['1.2',
, 'foo1.2'], + ['', 'foo', {a: true, b:
, c: 1.2, d: ''}, 'foo'], ['foo',
, '1.2foo'], // values inside elements - [
{true}{1.2}{
}
, '', 'foo'], [
, '', 'foo'], - [1.2, '',
{
}{'foo'}{true}
], ['1.2', '',
], + [
{true}{1.2}{
}
, '', 'foo'], [
, 'foo'], + [1.2, '',
{
}{'foo'}{true}
], ['1.2',
], ['',
{'foo'}{
}{true}
, 1.2], ['',
, '1.2'], [true,
{1.2}{''}{
}{'foo'}
, true, 1.2], [
, '1.2'], - ['', 'foo',
{true}{
}{1.2}{''}
, 'foo'], ['', 'foo',
, 'foo'] + ['', 'foo',
{true}{
}{1.2}{''}
, 'foo'], ['foo',
, 'foo'] ]); }); diff --git a/src/utils/flattenChildren.js b/src/utils/flattenChildren.js index 6240f10aee1ec..19161b82021e4 100644 --- a/src/utils/flattenChildren.js +++ b/src/utils/flattenChildren.js @@ -23,6 +23,8 @@ var ReactTextComponent = require('ReactTextComponent'); var traverseAllChildren = require('traverseAllChildren'); var warning = require('warning'); +var previousName = null; + /** * @param {function} traverseContext Context passed through traversal. * @param {?ReactComponent} child React child component. @@ -43,15 +45,20 @@ function flattenSingleChildIntoContext(traverseContext, child, name) { var type = typeof child; var normalizedValue; - if (type === 'string') { - normalizedValue = ReactTextComponent(child); - } else if (type === 'number') { - normalizedValue = ReactTextComponent('' + child); + if (type === 'string' || type === 'number') { + var previousValue = result[previousName]; + if (previousValue && previousValue.type === ReactTextComponent.type) { + normalizedValue = ReactTextComponent(previousValue.props + child); + name = previousName; + } else { + normalizedValue = ReactTextComponent('' + child); + } } else { normalizedValue = child; } result[name] = normalizedValue; + previousName = name; } } @@ -66,6 +73,7 @@ function flattenChildren(children) { } var result = {}; traverseAllChildren(children, flattenSingleChildIntoContext, result); + previousName = null; return result; }