@@ -32,100 +32,88 @@ export namespace LiftWrapper {
3232 export type RenderCache = React . DOMElement < any , any > | null
3333 export type WrapperSubscription = Subscription | null
3434
35- export interface SetRenderCache {
36- ( cache : RenderCache ) : void
37- }
38-
39- export interface SetSubscription {
40- ( sub : WrapperSubscription ) : void
41- }
35+ export class Renderer < TProps > extends React . PureComponent < Props < TProps > > {
36+ subscription : WrapperSubscription = null
37+ renderCache : RenderCache = null
4238
43- function useForceUpdate ( ) : ( ) => void {
44- return React . useReducer ( ( ) => ( { } ) , { } ) [ 1 ] as ( ) => void
45- }
39+ // variable to track sync emit from observable in Render{One, Many}.
40+ // prevent waste render during initial render & re-subscribe
41+ isSubscribed = false
4642
47- const unsubscribe = ( subscription : React . MutableRefObject < WrapperSubscription > ) => {
48- if ( subscription . current ) {
49- subscription . current . unsubscribe ( )
43+ // eslint-disable-next-line camelcase
44+ UNSAFE_componentWillMount ( ) {
45+ this . unsubscribe ( )
46+ this . subscribe ( this . props )
5047 }
51- }
5248
53- const useSubscribe = < T > (
54- newProps : Props < T > ,
55- subscription : React . MutableRefObject < WrapperSubscription > ,
56- renderCache : React . MutableRefObject < RenderCache >
57- ) => {
58- const forceUpdate = useForceUpdate ( )
59- const { props, component } = newProps
60-
61- let n = 0
62- // eslint-disable-next-line @typescript-eslint/no-use-before-define
63- walkObservables ( props , ( ) => n += 1 )
49+ // eslint-disable-next-line camelcase
50+ UNSAFE_componentWillReceiveProps ( nextProps : Props < TProps > ) {
51+ this . unsubscribe ( )
52+ this . subscribe ( nextProps )
53+ }
6454
65- // variable to track sync emit from observable in Render{One, Many}.
66- // prevent waste render during initial render & re-subscribe
67- let inSync = false
55+ componentWillUnmount ( ) {
56+ this . setSubscription ( null )
57+ }
6858
69- const setCache : SetRenderCache = cache => {
70- if ( renderCache . current === cache ) {
59+ setRenderCache ( cache : RenderCache ) : void {
60+ if ( this . renderCache === cache ) {
7161 return
7262 }
7363
74- renderCache . current = cache
64+ this . renderCache = cache
7565
76- if ( inSync ) {
77- forceUpdate ( )
66+ if ( this . isSubscribed ) {
67+ this . forceUpdate ( )
7868 }
7969 }
8070
81- const setSubscription : SetSubscription = sub => subscription . current = sub
82-
83- switch ( n ) {
84- case 0 :
85- setSubscription ( null )
86- // eslint-disable-next-line @typescript-eslint/no-use-before-define
87- setCache ( render ( component , props ) )
88- break
89-
90- // @NOTE original Calmm code below
91- // The created object is never used and it looks like that
92- // the useful work is done in the constructor.
93- // Could this be replaced by a regular closure? Perhaps using
94- // a class is an optimization?
95- case 1 :
96- new RenderOne ( renderCache , newProps , setCache , setSubscription ) // eslint-disable-line
97- break
98- default :
99- new RenderMany ( renderCache , newProps , setCache , setSubscription , n ) // eslint-disable-line
100- break
71+ setSubscription ( sub : WrapperSubscription ) : void {
72+ this . subscription = sub
10173 }
10274
103- inSync = true
104- }
75+ private unsubscribe ( ) {
76+ if ( this . subscription ) {
77+ this . subscription . unsubscribe ( )
78+ }
79+ }
10580
106- export const Renderer = < TProps > ( props : Props < TProps > ) => {
107- const _subscription = React . useRef < WrapperSubscription > ( null )
108- const _renderCache = React . useRef < RenderCache > ( null )
81+ private subscribe ( newProps : Props < TProps > ) {
82+ const { props, component } = newProps
10983
110- // concurrent mode support
111- // see https://codesandbox.io/s/x2p46v02z4?from-embed=&file=/src/BadCounter.jsx
112- const subscription = { current : _subscription . current }
113- const renderCache = { current : _renderCache . current }
84+ let n = 0
85+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
86+ walkObservables ( props , ( ) => n += 1 )
11487
115- React . useEffect ( ( ) => {
116- _subscription . current = subscription . current
117- _renderCache . current = renderCache . current
118- } )
88+ this . isSubscribed = false
11989
120- React . useEffect ( ( ) => ( ) => unsubscribe ( subscription ) , [ ] )
90+ switch ( n ) {
91+ case 0 :
92+ this . setSubscription ( null )
93+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
94+ this . setRenderCache ( render ( component , props ) )
95+ break
96+
97+ // @NOTE original Calmm code below
98+ // The created object is never used and it looks like that
99+ // the useful work is done in the constructor.
100+ // Could this be replaced by a regular closure? Perhaps using
101+ // a class is an optimization?
102+ case 1 :
103+ new RenderOne ( this , newProps ) // eslint-disable-line
104+ break
105+ default :
106+ new RenderMany ( this , newProps , n ) // eslint-disable-line
107+ break
108+ }
121109
122- unsubscribe ( subscription )
123- useSubscribe ( props , subscription , renderCache )
110+ this . isSubscribed = true
111+ }
124112
125- return renderCache . current || null
113+ render ( ) {
114+ return this . renderCache || null
115+ }
126116 }
127-
128- Renderer . displayName = 'LiftWrapper'
129117}
130118
131119// here we only say TProps, but a lifted component
@@ -346,10 +334,8 @@ class RenderOne<P> implements Subscription {
346334 private _receivedValue = false
347335
348336 constructor (
349- private renderCache : React . MutableRefObject < LiftWrapper . RenderCache > ,
350- private newProps : LiftWrapper . Props < P > ,
351- private setRenderCache : LiftWrapper . SetRenderCache ,
352- private setSubscription : LiftWrapper . SetSubscription
337+ private renderer : LiftWrapper . Renderer < P > ,
338+ private newProps : LiftWrapper . Props < P >
353339 ) {
354340 walkObservables (
355341 newProps . props ,
@@ -368,7 +354,7 @@ class RenderOne<P> implements Subscription {
368354 if ( DEV_ENV && ! this . _receivedValue )
369355 warnEmptyObservable ( getReactComponentName ( newProps . component ) )
370356
371- this . setSubscription ( this )
357+ this . renderer . setSubscription ( this )
372358 }
373359
374360 unsubscribe ( ) {
@@ -383,14 +369,14 @@ class RenderOne<P> implements Subscription {
383369 const { component, props } = this . newProps
384370 const renderCache = render ( component , props , [ value ] )
385371
386- if ( ! structEq ( this . renderCache . current , renderCache ) ) {
387- this . setRenderCache ( renderCache )
372+ if ( ! structEq ( this . renderer . renderCache , renderCache ) ) {
373+ this . renderer . setRenderCache ( renderCache )
388374 }
389375 }
390376
391377 private _handleCompleted = ( ) => {
392378 this . _innerSubscription = null
393- this . setSubscription ( null )
379+ this . renderer . setSubscription ( null )
394380 }
395381}
396382
@@ -404,10 +390,8 @@ class RenderMany<P> implements Subscription {
404390 private _innerSubscriptions : ( RxSubscription | null ) [ ]
405391
406392 constructor (
407- private renderCache : React . MutableRefObject < LiftWrapper . RenderCache > ,
393+ private renderer : LiftWrapper . Renderer < P > ,
408394 private newProps : LiftWrapper . Props < P > ,
409- private setRenderCache : LiftWrapper . SetRenderCache ,
410- private setSubscription : LiftWrapper . SetSubscription ,
411395 N : number
412396 ) {
413397 this . _innerSubscriptions = [ ]
@@ -447,7 +431,7 @@ class RenderMany<P> implements Subscription {
447431 break
448432 }
449433
450- this . setSubscription ( this )
434+ this . renderer . setSubscription ( this )
451435 }
452436
453437 unsubscribe ( ) {
@@ -471,8 +455,8 @@ class RenderMany<P> implements Subscription {
471455 const { component, props } = this . newProps
472456 const renderCache = render ( component , props , this . _values )
473457
474- if ( ! structEq ( this . renderCache . current , renderCache ) ) {
475- this . setRenderCache ( renderCache )
458+ if ( ! structEq ( this . renderer . renderCache , renderCache ) ) {
459+ this . renderer . setRenderCache ( renderCache )
476460 }
477461 }
478462
@@ -489,7 +473,7 @@ class RenderMany<P> implements Subscription {
489473 if ( this . _innerSubscriptions [ i ] )
490474 return
491475
492- this . setSubscription ( null )
476+ this . renderer . setSubscription ( null )
493477 }
494478}
495479
0 commit comments