@@ -151,6 +151,7 @@ function useRoutedComponentProps(
151
151
return useMemo ( ( ) => ( { ...baseChildProps , ...maybeRefProp } ) , [ baseChildProps , maybeRefProp ] ) ;
152
152
}
153
153
154
+ /** @hidden */
154
155
function useViewConfig ( ) {
155
156
const [ viewConfig , setViewConfig ] = useState < ReactViewConfig > ( ) ;
156
157
const viewConfigRef = useRef ( viewConfig ) ;
@@ -163,33 +164,49 @@ function useViewConfig() {
163
164
return { viewConfig, configUpdated } ;
164
165
}
165
166
167
+ /** @hidden */
166
168
function useReactHybridApi ( ref : React . Ref < unknown > , uiViewData : ActiveUIView , uiViewAddress : UIViewAddress ) {
167
169
const reactHybridApi = useRef ( { uiViewData, uiViewAddress } ) ;
168
170
reactHybridApi . current . uiViewData = uiViewData ;
169
171
reactHybridApi . current . uiViewAddress = uiViewAddress ;
170
172
useImperativeHandle ( ref , ( ) => reactHybridApi . current ) ;
171
173
}
172
174
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
+ */
177
182
function 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
+ }
189
203
}
190
- } , [ uiCanExit ] ) ;
204
+ }
191
205
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 ] ) ;
193
210
}
194
211
195
212
const View = forwardRef ( function View ( props : UIViewProps , forwardedRef ) {
0 commit comments