1
1
/* @flow */
2
+ // Extracted from: https://github.com/apollostack/react-apollo/blob/master/src/server.ts
2
3
3
4
// eslint-disable-next-line import/no-extraneous-dependencies
4
5
import { Children , Element } from 'react' ;
@@ -8,6 +9,8 @@ type Context = { [key: string]: any; };
8
9
type ElementVisitor =
9
10
( element : React$Element , instance : ?Function , context : Context ) => boolean | void ;
10
11
12
+ export const isPromise = ( x : any ) => typeof x === 'object' && typeof x . then === 'function' ;
13
+
11
14
// Recurse an React Element tree, running visitor on each element.
12
15
// If visitor returns `false`, don't call the element's render function
13
16
// or recurse into its child elements
@@ -16,16 +19,14 @@ export default function reactTreeWalker(
16
19
visitor : ElementVisitor ,
17
20
context : Context = { } ,
18
21
) {
19
- const Component = element . type ;
20
-
21
- // a stateless functional component or a class
22
- if ( typeof Component === 'function' ) {
22
+ // Is this element a Component?
23
+ if ( typeof element . type === 'function' ) {
24
+ const Component = element . type ;
23
25
const props = Object . assign ( { } , Component . defaultProps , element . props ) ;
24
26
let childContext = context ;
25
27
let child ;
26
28
27
- // Are we are a react class?
28
- // http://bit.ly/2j9Ifk3
29
+ // Is this a class component? (http://bit.ly/2j9Ifk3)
29
30
const isReactClassComponent = Component . prototype &&
30
31
( Component . prototype . isReactComponent || Component . prototype . isPureReactComponent ) ;
31
32
@@ -35,43 +36,57 @@ export default function reactTreeWalker(
35
36
instance . props = instance . props || props ;
36
37
instance . context = instance . context || context ;
37
38
38
- // Override setState to just change the state, not queue up an update.
39
- // (we can't do the default React thing as we aren't mounted "properly"
40
- // however, we don't need to re-render as well only support setState in
41
- // componentWillMount, which happens *before* render).
39
+ // Make the setState synchronous.
42
40
instance . setState = ( newState ) => {
43
41
instance . state = Object . assign ( { } , instance . state , newState ) ;
44
42
} ;
45
43
44
+ // Call componentWillMount if it exists.
46
45
if ( instance . componentWillMount ) {
47
46
instance . componentWillMount ( ) ;
48
47
}
49
48
49
+ // Ensure the child context is initialised if it is available. We will
50
+ // need to pass it down the tree.
50
51
if ( instance . getChildContext ) {
51
52
childContext = Object . assign ( { } , context , instance . getChildContext ( ) ) ;
52
53
}
53
54
55
+ // Hit up our visitor!
54
56
if ( visitor ( element , instance , context ) === false ) {
57
+ // Visitor returned false, indicating a desire to not traverse.
55
58
return ;
56
59
}
57
60
61
+ // Get the render output as the child.
58
62
child = instance . render ( ) ;
59
- } else { // just a stateless functional
63
+ } else {
64
+ // Stateless Functional Component
65
+
66
+ // Hit up our visitor!
60
67
if ( visitor ( element , null , context ) === false ) {
68
+ // Visitor returned false, indicating a desire to not traverse.
61
69
return ;
62
70
}
63
71
72
+ // Get the output for the function, as the child.
64
73
child = Component ( props , context ) ;
65
74
}
66
75
76
+ // Only continue walking if a child exists.
67
77
if ( child ) {
68
78
reactTreeWalker ( child , visitor , childContext ) ;
69
79
}
70
- } else { // a basic string or dom element, just get children
80
+ } else {
81
+ // This must be a basic element, such as a string or dom node.
82
+
83
+ // Hit up our visitor!
71
84
if ( visitor ( element , null , context ) === false ) {
85
+ // Visitor returned false, indicating a desire to not traverse.
72
86
return ;
73
87
}
74
88
89
+ // If the element has children then we will walk them.
75
90
if ( element . props && element . props . children ) {
76
91
Children . forEach ( element . props . children , ( child : any ) => {
77
92
if ( child ) {
0 commit comments