Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,12 @@ function constructNewChildrenArray(

if (isMounting) {
if (matchingIndex == -1) {
skew--;
//skew--;
if (newChildrenLength > oldChildrenLength) {
Comment thread
JoviDeCroock marked this conversation as resolved.
skew--;
} else if (newChildrenLength < oldChildrenLength) {
skew++;
}
}

// If we are mounting a DOM VNode, mark it for insertion
Expand Down Expand Up @@ -407,7 +412,7 @@ function findMatchingIndex(
(oldVNode != NULL && (oldVNode._flags & MATCHED) == 0 ? 1 : 0);

if (
oldVNode === NULL ||
(oldVNode === NULL && !childVNode.key) ||
Comment thread
JoviDeCroock marked this conversation as resolved.
Outdated
(oldVNode &&
key == oldVNode.key &&
type === oldVNode.type &&
Expand Down
181 changes: 181 additions & 0 deletions test/browser/keys.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -943,4 +943,185 @@ describe('keys', () => {

expect(scratch.innerHTML).to.eq(`<div>${expected(sorted)}</div>`);
});

it('should handle keyed replacements', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return (
<div>
<Comp key={props.y} i={1} />
{false}
<Comp i={2} />
<Comp i={3} />
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal([
'mounted 1',
'mounted 2',
'mounted 3',
'mounted 1'
]);
});

it('should handle hole prepend', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
{null}
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);
});

it('should handle hole replace', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return props.y === '1' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
{null}
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="1" />, scratch);
expect(actions).to.deep.equal([
'mounted 1',
'mounted 2',
'mounted 3',
'mounted 2'
]);
});

it('should handle hole insert', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
{null}
<Comp key={3} i={3} />
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);
});

it('should handle hole apppend', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return props.y === '2' ? (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
</div>
) : (
<div>
<Comp key={1} i={1} />
<Comp key={2} i={2} />
<Comp key={3} i={3} />
{null}
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);
});
});
29 changes: 29 additions & 0 deletions test/browser/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1967,4 +1967,33 @@ describe('render()', () => {
'<head><title>Test</title></head><body><p>Test</p></body>\n'
);
});

it('should not remount components when replacing a component with a falsy value in-between', () => {
const actions = [];
class Comp extends Component {
componentDidMount() {
actions.push('mounted ' + this.props.i);
}
render() {
return <div>Hello</div>;
}
}

const App = props => {
return (
<div>
{props.y === '1' ? <Comp i={1} /> : <div />}
{false}
<Comp i={2} />
<Comp i={3} />
</div>
);
};

render(<App y="1" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);

render(<App y="2" />, scratch);
expect(actions).to.deep.equal(['mounted 1', 'mounted 2', 'mounted 3']);
});
});