Skip to content
Permalink
Browse files

Fix reordering of children

If a container has children A and B and their order is reversed,
React will only trigger one reconciler method - appendChild.
There's no call to removeChild, because appendChild's behavior in
browsers removes the child that's being added from its last parent
node. This behavior wasn't supported by Ink before.

So, for example:

Render 1:
Container
- Child A
- Child B

Reconciler calls:
- appendChild(container, childA)
- appendChild(container, childB)

Render 2:
Container
- Child B
- Child A

Reconciler calls:
- appendChild(container, childA)

This last appendChild call will first remove childA from container
and then append it to the end of the list again, making childB first.
  • Loading branch information...
vadimdemedes committed Mar 9, 2019
1 parent 971a51c commit a022a38096ee7daa86aeef4c20cb76857ba38e77
Showing with 23 additions and 3 deletions.
  1. +21 −1 src/dom.js
  2. +2 −2 src/renderer.js
@@ -3,14 +3,32 @@ export const createNode = tagName => ({
nodeName: tagName.toUpperCase(),
style: {},
attributes: {},
childNodes: []
childNodes: [],
parentNode: null
});

export const appendChildNode = (node, childNode) => {
if (childNode.parentNode) {
removeChildNode(childNode.parentNode, childNode);
}

childNode.parentNode = node;

node.childNodes.push(childNode);
};

// Same as `appendChildNode`, but without removing child node from parent node
export const appendStaticNode = (node, childNode) => {
node.childNodes.push(childNode);
};

export const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
if (newChildNode.parentNode) {
removeChildNode(newChildNode.parentNode, newChildNode);
}

newChildNode.parentNode = node;

const index = node.childNodes.indexOf(beforeChildNode);
if (index >= 0) {
node.childNodes.splice(index, 0, newChildNode);
@@ -21,6 +39,8 @@ export const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
};

export const removeChildNode = (node, removeNode) => {
removeNode.parentNode = null

const index = node.childNodes.indexOf(removeNode);
if (index >= 0) {
node.childNodes.splice(index, 1);
@@ -1,6 +1,6 @@
import Yoga from 'yoga-layout-prebuilt';
import Output from './output';
import {createNode, appendChildNode} from './dom';
import {createNode, appendStaticNode} from './dom';
import buildLayout from './build-layout';
import renderNodeToOutput from './render-node-to-output';

@@ -49,7 +49,7 @@ export default ({terminalWidth}) => {
let staticOutput;
if (staticElements.length === 1) {
const rootNode = createNode('root');
appendChildNode(rootNode, staticElements[0]);
appendStaticNode(rootNode, staticElements[0], {woot: true});

const {yogaNode: staticYogaNode} = buildLayout(rootNode, {
config,

0 comments on commit a022a38

Please sign in to comment.
You can’t perform that action at this time.