@@ -223,6 +223,72 @@ describe('useSpring', () => {
223223 } )
224224 } )
225225
226+ // Regression tests for https://github.com/pmndrs/react-spring/issues/2361
227+ // (and the earlier https://github.com/pmndrs/react-spring/issues/2146).
228+ // A declarative `useSpring` with no ref should auto-animate on mount even
229+ // under StrictMode, whose double-mount (mount → simulated unmount → mount)
230+ // used to leave the controller stopped with an empty `updates` array.
231+ describe ( 'when a declarative props object is passed with no ref (StrictMode)' , ( ) => {
232+ it ( 'animates from→to on mount' , async ( ) => {
233+ const onStart = vi . fn ( )
234+ const onRest = vi . fn ( )
235+ let spring : SpringValue < number > | undefined
236+
237+ function Component ( ) {
238+ const springs = useSpring ( {
239+ from : { opacity : 0 } ,
240+ to : { opacity : 1 } ,
241+ config : { duration : 100 } ,
242+ onStart,
243+ onRest,
244+ } )
245+ spring = springs . opacity as unknown as SpringValue < number >
246+ return null
247+ }
248+
249+ await render (
250+ < React . StrictMode >
251+ < Component />
252+ </ React . StrictMode >
253+ )
254+ await advanceUntilIdle ( )
255+
256+ expect ( spring ?. get ( ) ) . toBe ( 1 )
257+ expect ( onStart ) . toHaveBeenCalledTimes ( 1 )
258+ expect ( onRest ) . toHaveBeenCalledTimes ( 1 )
259+ } )
260+
261+ it ( 'keeps a looped animation running on mount' , async ( ) => {
262+ const onStart = vi . fn ( )
263+ let spring : SpringValue < number > | undefined
264+
265+ function Component ( ) {
266+ const springs = useSpring ( {
267+ from : { x : 0 } ,
268+ to : { x : 100 } ,
269+ loop : true ,
270+ config : { duration : 100 } ,
271+ onStart,
272+ } )
273+ spring = springs . x as unknown as SpringValue < number >
274+ return null
275+ }
276+
277+ await render (
278+ < React . StrictMode >
279+ < Component />
280+ </ React . StrictMode >
281+ )
282+
283+ // A loop never goes idle, so step until it has driven the value forward.
284+ await advanceUntilValue ( spring ! , 50 )
285+
286+ expect ( spring ! . get ( ) ) . toBeGreaterThanOrEqual ( 50 )
287+ expect ( spring ! . isAnimating ) . toBe ( true )
288+ expect ( onStart ) . toHaveBeenCalled ( )
289+ } )
290+ } )
291+
226292 // Regression test for https://github.com/pmndrs/react-spring/issues/1638
227293 // The original bug (v9.2.4): a spring with initial value 0 would not
228294 // animate when api.start() was called from useLayoutEffect on first render.
0 commit comments