@@ -8,149 +8,157 @@ const getInitialState = () => ({
88 finishedAt : undefined
99} )
1010
11- const { Consumer, Provider } = React . createContext ( getInitialState ( ) )
12-
1311/**
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.
1814 */
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+ }
4528
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+ }
5332
54- cancel = ( ) => {
55- this . counter ++
56- this . setState ( { isLoading : false , startedAt : undefined } )
57- }
33+ componentWillUnmount ( ) {
34+ this . cancel ( )
35+ this . mounted = false
36+ }
5837
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 ) )
6244 }
63- return data
64- }
6545
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 ) )
6953 }
70- return error
71- }
7254
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+ }
7759
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+ }
8267
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
9474 }
9575
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
9879 }
9980
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
10284 }
10385
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+ }
105111 }
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- )
123112
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+ }
139163
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