@@ -8,149 +8,157 @@ const getInitialState = () => ({
8
8
finishedAt : undefined
9
9
} )
10
10
11
- const { Consumer, Provider } = React . createContext ( getInitialState ( ) )
12
-
13
11
/**
14
- * Renders only when promise is rejected.
15
- *
16
- * @prop {boolean } persist Show old error while loading
17
- * @prop {Function|Node } children Function (passing error and finishedAt) or React node
12
+ * createInstance allows you to create instances of Async that are bound to a specific promise.
13
+ * A unique instance also uses its own React context for better nesting capability.
18
14
*/
19
- class Async extends React . Component {
20
- mounted = false
21
- counter = 0
22
- args = [ ]
23
- state = getInitialState ( )
24
-
25
- componentDidMount ( ) {
26
- this . mounted = true
27
- this . load ( )
28
- }
29
-
30
- componentDidUpdate ( prevProps ) {
31
- if ( prevProps . watch !== this . props . watch ) this . load ( )
32
- }
33
-
34
- componentWillUnmount ( ) {
35
- this . cancel ( )
36
- this . mounted = false
37
- }
38
-
39
- load = ( ) => {
40
- if ( ! this . props . promiseFn ) return
41
- this . counter ++
42
- this . setState ( { isLoading : true , startedAt : new Date ( ) , finishedAt : undefined } )
43
- return this . props . promiseFn ( ) . then ( this . onResolve ( this . counter ) , this . onReject ( this . counter ) )
44
- }
15
+ export const createInstance = ( defaultProps = { } ) => {
16
+ const { Consumer, Provider } = React . createContext ( getInitialState ( ) )
17
+
18
+ class Async extends React . Component {
19
+ mounted = false
20
+ counter = 0
21
+ args = [ ]
22
+ state = getInitialState ( )
23
+
24
+ componentDidMount ( ) {
25
+ this . mounted = true
26
+ this . load ( )
27
+ }
45
28
46
- run = ( ...args ) => {
47
- if ( ! this . props . deferFn ) return
48
- this . counter ++
49
- this . args = args
50
- this . setState ( { isLoading : true , startedAt : new Date ( ) , finishedAt : undefined } )
51
- return this . props . deferFn ( ...args ) . then ( this . onResolve ( this . counter ) , this . onReject ( this . counter ) )
52
- }
29
+ componentDidUpdate ( prevProps ) {
30
+ if ( prevProps . watch !== this . props . watch ) this . load ( )
31
+ }
53
32
54
- cancel = ( ) => {
55
- this . counter ++
56
- this . setState ( { isLoading : false , startedAt : undefined } )
57
- }
33
+ componentWillUnmount ( ) {
34
+ this . cancel ( )
35
+ this . mounted = false
36
+ }
58
37
59
- onResolve = counter => data => {
60
- if ( this . mounted && this . counter === counter ) {
61
- this . setData ( data , ( ) => this . props . onResolve && this . props . onResolve ( data ) )
38
+ load = ( ) => {
39
+ const promiseFn = this . props . promiseFn || defaultProps . promiseFn
40
+ if ( ! promiseFn ) return
41
+ this . counter ++
42
+ this . setState ( { isLoading : true , startedAt : new Date ( ) , finishedAt : undefined } )
43
+ return promiseFn ( ) . then ( this . onResolve ( this . counter ) , this . onReject ( this . counter ) )
62
44
}
63
- return data
64
- }
65
45
66
- onReject = counter => error => {
67
- if ( this . mounted && this . counter === counter ) {
68
- this . setError ( error , ( ) => this . props . onReject && this . props . onReject ( error ) )
46
+ run = ( ...args ) => {
47
+ const deferFn = this . props . deferFn || defaultProps . deferFn
48
+ if ( ! deferFn ) return
49
+ this . counter ++
50
+ this . args = args
51
+ this . setState ( { isLoading : true , startedAt : new Date ( ) , finishedAt : undefined } )
52
+ return deferFn ( ...args ) . then ( this . onResolve ( this . counter ) , this . onReject ( this . counter ) )
69
53
}
70
- return error
71
- }
72
54
73
- setData = ( data , callback ) => {
74
- this . setState ( { data , error : undefined , isLoading : false , finishedAt : new Date ( ) } , callback )
75
- return data
76
- }
55
+ cancel = ( ) => {
56
+ this . counter ++
57
+ this . setState ( { isLoading : false , startedAt : undefined } )
58
+ }
77
59
78
- setError = ( error , callback ) => {
79
- this . setState ( { error, isLoading : false , finishedAt : new Date ( ) } , callback )
80
- return error
81
- }
60
+ onResolve = counter => data => {
61
+ if ( this . mounted && this . counter === counter ) {
62
+ const onResolve = this . props . onResolve || defaultProps . onResolve
63
+ this . setData ( data , ( ) => onResolve && onResolve ( data ) )
64
+ }
65
+ return data
66
+ }
82
67
83
- render ( ) {
84
- const renderProps = {
85
- ...this . state ,
86
- cancel : this . cancel ,
87
- run : this . run ,
88
- reload : ( ) => {
89
- this . load ( )
90
- this . run ( ...this . args )
91
- } ,
92
- setData : this . setData ,
93
- setError : this . setError
68
+ onReject = counter => error => {
69
+ if ( this . mounted && this . counter === counter ) {
70
+ const onReject = this . props . onReject || defaultProps . onReject
71
+ this . setError ( error , ( ) => onReject && onReject ( error ) )
72
+ }
73
+ return error
94
74
}
95
75
96
- if ( typeof this . props . children === "function" ) {
97
- return this . props . children ( renderProps )
76
+ setData = ( data , callback ) => {
77
+ this . setState ( { data, error : undefined , isLoading : false , finishedAt : new Date ( ) } , callback )
78
+ return data
98
79
}
99
80
100
- if ( this . props . children ) {
101
- return < Provider value = { renderProps } > { this . props . children } </ Provider >
81
+ setError = ( error , callback ) => {
82
+ this . setState ( { error, isLoading : false , finishedAt : new Date ( ) } , callback )
83
+ return error
102
84
}
103
85
104
- return null
86
+ render ( ) {
87
+ const { children } = this . props
88
+
89
+ const renderProps = {
90
+ ...this . state ,
91
+ cancel : this . cancel ,
92
+ run : this . run ,
93
+ reload : ( ) => {
94
+ this . load ( )
95
+ this . run ( ...this . args )
96
+ } ,
97
+ setData : this . setData ,
98
+ setError : this . setError
99
+ }
100
+
101
+ if ( typeof children === "function" ) {
102
+ return < Provider value = { renderProps } > { children ( renderProps ) } </ Provider >
103
+ }
104
+
105
+ if ( children !== undefined && children !== null ) {
106
+ return < Provider value = { renderProps } > { children } </ Provider >
107
+ }
108
+
109
+ return null
110
+ }
105
111
}
106
- }
107
-
108
- /**
109
- * Renders only while loading.
110
- *
111
- * @prop {boolean } initial Show only on initial load (data is undefined)
112
- * @prop {Function|Node } children Function (passing props) or React node
113
- */
114
- Async . Loading = ( { children, initial } ) => (
115
- < Consumer >
116
- { props => {
117
- if ( ! props . isLoading ) return null
118
- if ( initial && props . data !== undefined ) return null
119
- return typeof children === "function" ? children ( props ) : children || null
120
- } }
121
- </ Consumer >
122
- )
123
112
124
- /**
125
- * Renders only when promise is resolved.
126
- *
127
- * @prop {boolean } persist Show old data while loading
128
- * @prop {Function|Node } children Function (passing data and props) or React node
129
- */
130
- Async . Resolved = ( { children, persist } ) => (
131
- < Consumer >
132
- { props => {
133
- if ( props . data === undefined ) return null
134
- if ( props . isLoading && ! persist ) return null
135
- return typeof children === "function" ? children ( props . data , props ) : children || null
136
- } }
137
- </ Consumer >
138
- )
113
+ /**
114
+ * Renders only while loading.
115
+ *
116
+ * @prop {boolean } initial Show only on initial load (data is undefined)
117
+ * @prop {Function|Node } children Function (passing props) or React node
118
+ */
119
+ Async . Loading = ( { children, initial } ) => (
120
+ < Consumer >
121
+ { props => {
122
+ if ( ! props . isLoading ) return null
123
+ if ( initial && props . data !== undefined ) return null
124
+ return typeof children === "function" ? children ( props ) : children || null
125
+ } }
126
+ </ Consumer >
127
+ )
128
+
129
+ /**
130
+ * Renders only when promise is resolved.
131
+ *
132
+ * @prop {boolean } persist Show old data while loading
133
+ * @prop {Function|Node } children Function (passing data and props) or React node
134
+ */
135
+ Async . Resolved = ( { children, persist } ) => (
136
+ < Consumer >
137
+ { props => {
138
+ if ( props . data === undefined ) return null
139
+ if ( props . isLoading && ! persist ) return null
140
+ return typeof children === "function" ? children ( props . data , props ) : children || null
141
+ } }
142
+ </ Consumer >
143
+ )
144
+
145
+ /**
146
+ * Renders only when promise is rejected.
147
+ *
148
+ * @prop {boolean } persist Show old error while loading
149
+ * @prop {Function|Node } children Function (passing error and props) or React node
150
+ */
151
+ Async . Rejected = ( { children, persist } ) => (
152
+ < Consumer >
153
+ { props => {
154
+ if ( props . error === undefined ) return null
155
+ if ( props . isLoading && ! persist ) return null
156
+ return typeof children === "function" ? children ( props . error , props ) : children || null
157
+ } }
158
+ </ Consumer >
159
+ )
160
+
161
+ return Async
162
+ }
139
163
140
- /**
141
- * Renders only when promise is rejected.
142
- *
143
- * @prop {boolean } persist Show old error while loading
144
- * @prop {Function|Node } children Function (passing error and props) or React node
145
- */
146
- Async . Rejected = ( { children, persist } ) => (
147
- < Consumer >
148
- { props => {
149
- if ( props . error === undefined ) return null
150
- if ( props . isLoading && ! persist ) return null
151
- return typeof children === "function" ? children ( props . error , props ) : children || null
152
- } }
153
- </ Consumer >
154
- )
155
-
156
- export default Async
164
+ export default createInstance ( )
0 commit comments