Skip to content

Commit 6ddcc07

Browse files
authored
Merge pull request #10 from dharFr/preact8-null-children
Error thrown with Preact8
2 parents fb91bd4 + 802121a commit 6ddcc07

File tree

4 files changed

+106
-6
lines changed

4 files changed

+106
-6
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ env:
88
-
99
- PREACT_VERSION=5.7.0
1010
- PREACT_VERSION=6.0.2
11+
- PREACT_VERSION=7.2.1
12+
- PREACT_VERSION=8.1.0

src/CSSTransitionGroup.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
import { h, cloneElement, Component } from 'preact';
15-
import { getKey } from './util';
15+
import { getKey, filterNullChildren } from './util';
1616
import { mergeChildMappings, isShownInChildren, isShownInChildrenByKey, inChildren, inChildrenByKey } from './TransitionChildMapping';
1717
import { CSSTransitionGroupChild } from './CSSTransitionGroupChild';
1818

@@ -42,10 +42,10 @@ export class CSSTransitionGroup extends Component {
4242
}
4343

4444
componentWillReceiveProps({ children, exclusive, showProp }) {
45-
let nextChildMapping = (children || []).slice();
45+
let nextChildMapping = filterNullChildren(children || []).slice();
4646

4747
// last props children if exclusive
48-
let prevChildMapping = exclusive ? this.props.children : this.state.children;
48+
let prevChildMapping = filterNullChildren(exclusive ? this.props.children : this.state.children);
4949

5050
let newChildren = mergeChildMappings(
5151
prevChildMapping,
@@ -118,7 +118,7 @@ export class CSSTransitionGroup extends Component {
118118

119119
_handleDoneEntering(key) {
120120
delete this.currentlyTransitioningKeys[key];
121-
let currentChildMapping = this.props.children,
121+
let currentChildMapping = filterNullChildren(this.props.children),
122122
showProp = this.props.showProp;
123123
if (!currentChildMapping || (
124124
!showProp && !inChildrenByKey(currentChildMapping, key)
@@ -157,7 +157,7 @@ export class CSSTransitionGroup extends Component {
157157
_handleDoneLeaving(key) {
158158
delete this.currentlyTransitioningKeys[key];
159159
let showProp = this.props.showProp,
160-
currentChildMapping = this.props.children;
160+
currentChildMapping = filterNullChildren(this.props.children);
161161
if (showProp && currentChildMapping &&
162162
isShownInChildrenByKey(currentChildMapping, key, showProp)) {
163163
this.performEnter(key);
@@ -200,7 +200,7 @@ export class CSSTransitionGroup extends Component {
200200
render({ component:Component, transitionName, transitionEnter, transitionLeave, children:c, ...props }, { children }) {
201201
return (
202202
<Component {...props}>
203-
{ children.map(this.renderChild) }
203+
{ filterNullChildren(children).map(this.renderChild) }
204204
</Component>
205205
);
206206
}

src/util.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ export function getComponentBase(component) {
99
export function onlyChild(children) {
1010
return children && children[0];
1111
}
12+
13+
export function filterNullChildren(children) {
14+
return children && children.filter(i => i !== null);
15+
}

tests/index.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,40 @@ class SVGList extends Component {
8383
}
8484
}
8585

86+
class NullChildren extends Component {
87+
88+
state = {
89+
items: [
90+
{ displayed: true, item: 'hello'},
91+
{ displayed: true, item: 'world'},
92+
{ displayed: false, item: 'click'},
93+
{ displayed: true, item: 'me'}
94+
]
95+
};
96+
97+
toggleDisplay(i) {
98+
let { items } = this.state;
99+
const item = items[i];
100+
item.displayed = !item.displayed;
101+
this.setState({ items });
102+
}
103+
104+
render(_, { items }) {
105+
return (
106+
<div className='root'>
107+
<CSSTransitionGroup transitionName="example">
108+
{null}
109+
110+
{ items.map( ({displayed, item}, i) => (
111+
displayed ? <Todo key={item} onClick={this.toggleDisplay.bind(this, i)}>
112+
{item}
113+
</Todo> : null
114+
)) }
115+
</CSSTransitionGroup>
116+
</div>
117+
);
118+
}
119+
}
86120

87121
const Nothing = () => null;
88122

@@ -204,3 +238,63 @@ describe('CSSTransitionGroup: SVG', () => {
204238
}, 1400);
205239
});
206240
});
241+
242+
describe('CSSTransitionGroup: NullChildren', () => {
243+
let container = document.createElement('div'),
244+
list, root;
245+
document.body.appendChild(container);
246+
247+
let $ = s => [].slice.call(container.querySelectorAll(s));
248+
249+
beforeEach( () => {
250+
root = render(<div><Nothing /></div>, container, root);
251+
root = render(<div><NullChildren ref={c => list=c} /></div>, container, root);
252+
});
253+
254+
afterEach( () => {
255+
list = null;
256+
});
257+
258+
it('create works', () => {
259+
expect($('.item')).to.have.length(3);
260+
});
261+
262+
it('transitionLeave works', done => {
263+
// this.timeout(5999);
264+
list.toggleDisplay(1);
265+
266+
// make sure -leave class was added
267+
setTimeout( () => {
268+
expect($('.item')).to.have.length(3);
269+
270+
expect($('.item')[1].className).to.contain('example-leave');
271+
expect($('.item')[1].className).to.contain('example-leave-active');
272+
}, 100);
273+
274+
// then make sure it's gone
275+
setTimeout( () => {
276+
expect($('.item')).to.have.length(2);
277+
done();
278+
}, 1400);
279+
});
280+
281+
it('transitionEnter works', done => {
282+
// this.timeout(5999);
283+
list.toggleDisplay(2);
284+
285+
setTimeout( () => {
286+
expect($('.item')).to.have.length(4);
287+
expect($('.item')[2].className).to.contain('example-enter');
288+
expect($('.item')[2].className).to.contain('example-enter-active');
289+
}, 500);
290+
291+
setTimeout( () => {
292+
expect($('.item')).to.have.length(4);
293+
294+
expect($('.item')[3].className).not.to.contain('example-enter');
295+
expect($('.item')[3].className).not.to.contain('example-enter-active');
296+
297+
done();
298+
}, 1400);
299+
});
300+
});

0 commit comments

Comments
 (0)