-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.js
67 lines (56 loc) · 2.07 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import React from 'react';
import PropTypes from 'prop-types';
export default function Composer({
components = [],
children,
renderPropName,
mapResult
}) {
if (typeof children !== 'function') {
return null;
}
// This is the argument that we pass into `children`.
const results = [];
// This is the list of components, reversed. We reverse them because the
// component that you list last will be the highest in the tree.
const reversedComponents = components.reverse();
function chainComponents(childrenComponents) {
// When we reach the end of our `childrenComponents`, we can render out
// the response array.
if (childrenComponents.length === 0) {
return children([...results]);
}
const componentIndex = childrenComponents.length - 1;
const component = components[componentIndex];
// This is the index of where we should place the response within `results`.
// It's not the same as `componentIndex` because we reversed the components when
// rendering out the components.
// In a sense, it can be thought of as the "reverse" index of `componentIndex`.
const responseIndex = reversedComponents.length - childrenComponents.length;
// We create a clone of the childrenComponents so that subsequent calls to `chidlren`
// render the same tree. If we modified `reversedComponents` directly, then the tree would
// be different with each call to `children`.
const childrenComponentsClone = [...childrenComponents];
childrenComponentsClone.pop();
return React.cloneElement(component, {
[renderPropName]() {
if (mapResult) {
results[responseIndex] = mapResult.apply(null, arguments);
} else {
results[responseIndex] = arguments[0];
}
return chainComponents(childrenComponentsClone);
}
});
}
return chainComponents(reversedComponents);
}
Composer.propTypes = {
children: PropTypes.func,
components: PropTypes.array,
renderPropName: PropTypes.string,
mapResult: PropTypes.func
};
Composer.defaultProps = {
renderPropName: 'children'
};