@samitouri / QOS-React-2 / commits / 1112f1a003
Fork 0

The library for web and native user interfaces.

React onlyChild utility.

Small utility that extracts and validates that there is only a single child passed to a React composite component. The benefit here is that we abstract away *how* the children are actually stored while we iterate on different approaches. This way we won't break callsites as we try different ideas. When we settle on a final approach, all of these callsites will still work.

CommitSyncScript committed Jun 14, 2013 at 16:45 UTC 1112f1a00305626377f0f9402f139622c57be014
2 files changed +122
src/utils/__tests__/onlyChild-test.js new
+89
@@ -0,0 +1,89 @@
1 +/**
2 + * @emails react-core
3 + * @jsx React.DOM
4 + */
5 +
6 +"use strict";
7 +
8 +describe('onlyChild', function() {
9 +
10 + var React;
11 + var onlyChild;
12 + var WrapComponent;
13 +
14 + beforeEach(function() {
15 + React = require('React');
16 + onlyChild = require('onlyChild');
17 + WrapComponent = React.createClass({
18 + render: function() {
19 + return (
20 + <div>
21 + {onlyChild(this.props.children, this.props.mapFn, this)}
22 + </div>
23 + );
24 + }
25 + });
26 + });
27 +
28 + it('should fail when passed two children', function() {
29 + expect(function() {
30 + var instance =
31 + <WrapComponent>
32 + <div />
33 + <span />
34 + </WrapComponent>;
35 + onlyChild(instance.props.children);
36 + }).toThrow();
37 + });
38 +
39 + it('should fail when passed nully values', function() {
40 + expect(function() {
41 + var instance =
42 + <WrapComponent>
43 + {null}
44 + </WrapComponent>;
45 + onlyChild(instance.props.children);
46 + }).toThrow();
47 +
48 + expect(function() {
49 + var instance =
50 + <WrapComponent>
51 + {undefined}
52 + </WrapComponent>;
53 + onlyChild(instance.props.children);
54 + }).toThrow();
55 + });
56 +
57 + it('should fail when key/value objects', function() {
58 + expect(function() {
59 + var instance =
60 + <WrapComponent>
61 + {{oneThing: <span />}}
62 + </WrapComponent>;
63 + onlyChild(instance.props.children);
64 + }).toThrow();
65 + });
66 +
67 +
68 + it('should not fail when passed interpolated single child', function() {
69 + expect(function() {
70 + var instance =
71 + <WrapComponent>
72 + {<span />}
73 + </WrapComponent>;
74 + onlyChild(instance.props.children);
75 + }).not.toThrow();
76 + });
77 +
78 +
79 + it('should return the only child', function() {
80 + expect(function() {
81 + var instance =
82 + <WrapComponent>
83 + <span />
84 + </WrapComponent>;
85 + onlyChild(instance.props.children);
86 + }).not.toThrow();
87 + });
88 +
89 +});
src/utils/onlyChild.js new
+33
@@ -0,0 +1,33 @@
1 +/**
2 + * @providesModule onlyChild
3 + */
4 +"use strict";
5 +
6 +var ReactComponent = require('ReactComponent');
7 +
8 +var invariant = require('invariant');
9 +
10 +/**
11 + * Returns the first child in a collection of children and verifies that there
12 + * is only one child in the collection. The current implementation of this
13 + * function assumes that children have been flattened, but the purpose of this
14 + * helper function is to abstract away the particular structure of children.
15 + *
16 + * @param {?object} children Child collection structure.
17 + * @return {ReactComponent} The first and only `ReactComponent` contained in the
18 + * structure.
19 + */
20 +function onlyChild(children) {
21 + invariant(Array.isArray(children), 'onlyChild must be passed a valid Array.');
22 + invariant(
23 + children.length === 1,
24 + 'onlyChild must be passed an Array with exactly one child.'
25 + );
26 + invariant(
27 + ReactComponent.isValidComponent(children[0]),
28 + 'onlyChild must be passed an Array with exactly one child.'
29 + );
30 + return children[0];
31 +}
32 +
33 +module.exports = onlyChild;