From 07a48e544dff5b80926b7ef9eb0e05dfb1024476 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 5 May 2017 12:32:26 -0400 Subject: [PATCH 1/4] Import methods to test from source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise changes aren’t reflected until build --- index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.test.js b/index.test.js index 5217f9d..1d8140c 100644 --- a/index.test.js +++ b/index.test.js @@ -4,7 +4,7 @@ import { JSDOM } from 'jsdom' import { createElement } from 'react' import { renderToStaticMarkup } from 'react-dom/server' -import { nodeToReact } from '.' +import { nodeToReact } from './index' const { window } = new JSDOM() const { document } = window From cc3d1989c7d3f4747088ce14a10eb666e0dacdd3 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 5 May 2017 12:33:32 -0400 Subject: [PATCH 2/4] Assign and reuse element key by child index --- index.js | 10 +++++++++- index.test.js | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index bcab414..c60fc68 100644 --- a/index.js +++ b/index.js @@ -111,7 +111,11 @@ export function attributeListToReact (attributeList) { } export function nodeListToReact (nodeList, createElement) { - return [...nodeList].reduce((accumulator, node) => { + return [...nodeList].reduce((accumulator, node, index) => { + if (!node._domReactKey) { + node._domReactKey = String(index) + } + const child = nodeToReact(node, createElement) if (Array.isArray(child)) { @@ -146,6 +150,10 @@ export function nodeToReact (node, createElement) { props = attributeListToReact(node.attributes) } + if (node._domReactKey) { + props.key = node._domReactKey + } + if (node.hasChildNodes()) { children = nodeListToReact(node.childNodes, createElement) } diff --git a/index.test.js b/index.test.js index 1d8140c..5155893 100644 --- a/index.test.js +++ b/index.test.js @@ -4,7 +4,7 @@ import { JSDOM } from 'jsdom' import { createElement } from 'react' import { renderToStaticMarkup } from 'react-dom/server' -import { nodeToReact } from './index' +import { nodeListToReact, nodeToReact } from './index' const { window } = new JSDOM() const { document } = window @@ -95,4 +95,29 @@ describe('nodeToReact()', () => { } }))) }) + + describe('nodeListToReact', () => { + it('should return array of React element with key assigned by child index', () => { + document.body.innerHTML = '

test test

test' + const elements = nodeListToReact(document.body.childNodes, createElement) + + equal('0', elements[0].key) + equal('string', typeof elements[0].props.children[0]) + equal('1', elements[0].props.children[1].key) + equal('1', elements[1].key) + }) + + it('should reuse assigned key for same elements reference', () => { + document.body.innerHTML = '' + const list = document.body.firstChild + let elements = nodeListToReact(list.childNodes, createElement) + + // Rearrange second list item before first + list.insertBefore(list.lastChild, list.firstChild) + + elements = nodeListToReact(list.childNodes, createElement) + equal('1', elements[0].key) + equal('0', elements[1].key) + }) + }) }) From 7f62a0cdff0cb9f0782dcca3eba90eb62e8ef7a8 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 5 May 2017 16:21:03 -0400 Subject: [PATCH 3/4] Assign key by prefixed global counter --- index.js | 6 ++++-- index.test.js | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index c60fc68..cfd1ace 100644 --- a/index.js +++ b/index.js @@ -110,10 +110,12 @@ export function attributeListToReact (attributeList) { }, {}) } +let keyCounter = 0 + export function nodeListToReact (nodeList, createElement) { - return [...nodeList].reduce((accumulator, node, index) => { + return [...nodeList].reduce((accumulator, node) => { if (!node._domReactKey) { - node._domReactKey = String(index) + node._domReactKey = '_domReact' + String(keyCounter++) } const child = nodeToReact(node, createElement) diff --git a/index.test.js b/index.test.js index 5155893..6de5045 100644 --- a/index.test.js +++ b/index.test.js @@ -1,5 +1,5 @@ import { describe, it } from 'mocha' -import { equal } from 'assert' +import { equal, ok } from 'assert' import { JSDOM } from 'jsdom' import { createElement } from 'react' import { renderToStaticMarkup } from 'react-dom/server' @@ -97,14 +97,19 @@ describe('nodeToReact()', () => { }) describe('nodeListToReact', () => { + const rxKey = /^_domReact\d+$/ + function assertKey (key) { + ok(rxKey.test(key), 'expected to match key pattern ' + rxKey.toString()) + } + it('should return array of React element with key assigned by child index', () => { document.body.innerHTML = '

test test

test' const elements = nodeListToReact(document.body.childNodes, createElement) - equal('0', elements[0].key) + assertKey(elements[0].key) equal('string', typeof elements[0].props.children[0]) - equal('1', elements[0].props.children[1].key) - equal('1', elements[1].key) + assertKey(elements[0].props.children[1].key) + assertKey(elements[1].key) }) it('should reuse assigned key for same elements reference', () => { @@ -116,8 +121,8 @@ describe('nodeToReact()', () => { list.insertBefore(list.lastChild, list.firstChild) elements = nodeListToReact(list.childNodes, createElement) - equal('1', elements[0].key) - equal('0', elements[1].key) + assertKey(elements[0].key) + assertKey(elements[1].key) }) }) }) From c91849c116d18a7bf8988c2ce401fe9c2d36bc8b Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 5 May 2017 16:24:46 -0400 Subject: [PATCH 4/4] Ensure reused keys match reverse of before MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of course they’re matched keys, but that’s not what the test is accomplishing; instead ensure they’re _reused_ --- index.test.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/index.test.js b/index.test.js index 6de5045..e67033e 100644 --- a/index.test.js +++ b/index.test.js @@ -1,5 +1,5 @@ import { describe, it } from 'mocha' -import { equal, ok } from 'assert' +import { equal, ok, deepEqual } from 'assert' import { JSDOM } from 'jsdom' import { createElement } from 'react' import { renderToStaticMarkup } from 'react-dom/server' @@ -115,14 +115,16 @@ describe('nodeToReact()', () => { it('should reuse assigned key for same elements reference', () => { document.body.innerHTML = '
  • one
  • two
' const list = document.body.firstChild - let elements = nodeListToReact(list.childNodes, createElement) + const before = nodeListToReact(list.childNodes, createElement) // Rearrange second list item before first list.insertBefore(list.lastChild, list.firstChild) - elements = nodeListToReact(list.childNodes, createElement) - assertKey(elements[0].key) - assertKey(elements[1].key) + const after = nodeListToReact(list.childNodes, createElement) + deepEqual( + before.map(({key}) => key), + after.map(({key}) => key).reverse() + ) }) }) })