@@ -151,6 +151,7 @@ function useRoutedComponentProps(
151151 return useMemo ( ( ) => ( { ...baseChildProps , ...maybeRefProp } ) , [ baseChildProps , maybeRefProp ] ) ;
152152}
153153
154+ /** @hidden */
154155function useViewConfig ( ) {
155156 const [ viewConfig , setViewConfig ] = useState < ReactViewConfig > ( ) ;
156157 const viewConfigRef = useRef ( viewConfig ) ;
@@ -163,33 +164,49 @@ function useViewConfig() {
163164 return { viewConfig, configUpdated } ;
164165}
165166
167+ /** @hidden */
166168function useReactHybridApi ( ref : React . Ref < unknown > , uiViewData : ActiveUIView , uiViewAddress : UIViewAddress ) {
167169 const reactHybridApi = useRef ( { uiViewData, uiViewAddress } ) ;
168170 reactHybridApi . current . uiViewData = uiViewData ;
169171 reactHybridApi . current . uiViewAddress = uiViewAddress ;
170172 useImperativeHandle ( ref , ( ) => reactHybridApi . current ) ;
171173}
172174
173- // If a class component is being rendered, wire up its uiCanExit method
174- // Return a { ref: Ref<ClassComponentInstance> } if passed a component class
175- // Return an empty object {} if passed anything else
176- // The returned object should be spread as props onto the child component
175+ /**
176+ * If a class component is being rendered, wire up its uiCanExit method
177+ * Return a { ref: Ref<ClassComponentInstance> } if passed a component class
178+ * Return an empty object {} if passed anything else
179+ * The returned object should be spread as props onto the child component
180+ * @hidden
181+ */
177182function useUiCanExitClassComponentHook ( router : UIRouter , stateName : string , maybeComponentClass : any ) {
178- const ref = useRef < any > ( ) ;
179- const isComponentClass = maybeComponentClass ?. prototype ?. render || maybeComponentClass ?. render ;
180- const componentInstance = isComponentClass && ref . current ;
181- const uiCanExit = componentInstance ?. uiCanExit ;
182-
183- useEffect ( ( ) => {
184- if ( uiCanExit ) {
185- const deregister = router . transitionService . onBefore ( { exiting : stateName } , uiCanExit . bind ( ref . current ) ) ;
186- return ( ) => deregister ( ) ;
187- } else {
188- return ( ) => undefined ;
183+ // Use refs and run the callback outside of any render pass
184+ const componentInstanceRef = useRef < any > ( ) ;
185+ const deregisterRef = useRef < Function > ( ( ) => undefined ) ;
186+
187+ function callbackRef ( componentInstance ) {
188+ // Use refs
189+ const previous = componentInstanceRef . current ;
190+ const deregisterPreviousTransitionHook = deregisterRef . current ;
191+
192+ if ( previous !== componentInstance ) {
193+ componentInstanceRef . current = componentInstance ;
194+ deregisterPreviousTransitionHook ( ) ;
195+
196+ const uiCanExit = componentInstance ?. uiCanExit ;
197+ if ( uiCanExit ) {
198+ const boundCallback = uiCanExit . bind ( componentInstance ) ;
199+ deregisterRef . current = router . transitionService . onBefore ( { exiting : stateName } , boundCallback ) ;
200+ } else {
201+ deregisterRef . current = ( ) => undefined ;
202+ }
189203 }
190- } , [ uiCanExit ] ) ;
204+ }
191205
192- return useMemo ( ( ) => ( isComponentClass ? { ref } : undefined ) , [ isComponentClass , ref ] ) ;
206+ return useMemo ( ( ) => {
207+ const isComponentClass = maybeComponentClass ?. prototype ?. render || maybeComponentClass ?. render ;
208+ return isComponentClass ? { ref : callbackRef } : undefined ;
209+ } , [ maybeComponentClass ] ) ;
193210}
194211
195212const View = forwardRef ( function View ( props : UIViewProps , forwardedRef ) {
0 commit comments