Skip to content

Commit 8ed5a42

Browse files
committed
fix: memoize the ref function in withAnimated
1 parent 7a12d23 commit 8ed5a42

File tree

1 file changed

+24
-20
lines changed

1 file changed

+24
-20
lines changed

packages/animated/src/withAnimated.tsx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react'
2-
import { forwardRef, useRef, Ref } from 'react'
2+
import { forwardRef, useRef, Ref, useCallback } from 'react'
33
import { useLayoutEffect } from 'react-layout-effect'
44
import { is, each, useForceUpdate, ElementType, FluidConfig } from 'shared'
55

@@ -8,14 +8,26 @@ import { HostConfig } from './createHost'
88

99
export type AnimatableComponent = string | Exclude<ElementType, string>
1010

11-
export const withAnimated = (Component: any, host: HostConfig) =>
12-
forwardRef((rawProps: any, ref: Ref<any>) => {
11+
export const withAnimated = (Component: any, host: HostConfig) => {
12+
const hasInstance: boolean =
13+
// Function components must use "forwardRef" to avoid being
14+
// re-rendered on every animation frame.
15+
!is.fun(Component) ||
16+
(Component.prototype && Component.prototype.isReactComponent)
17+
18+
return forwardRef((givenProps: any, givenRef: Ref<any>) => {
1319
const instanceRef = useRef<any>(null)
14-
const hasInstance: boolean =
15-
// Function components must use "forwardRef" to avoid being
16-
// re-rendered on every animation frame.
17-
!is.fun(Component) ||
18-
(Component.prototype && Component.prototype.isReactComponent)
20+
21+
// The `hasInstance` value is constant, so we can safely avoid
22+
// the `useCallback` invocation when `hasInstance` is false.
23+
const ref =
24+
hasInstance &&
25+
useCallback(
26+
(value: any) => {
27+
instanceRef.current = updateRef(givenRef, value)
28+
},
29+
[givenRef]
30+
)
1931

2032
const forceUpdate = useForceUpdate()
2133
const props = new AnimatedProps(() => {
@@ -35,25 +47,17 @@ export const withAnimated = (Component: any, host: HostConfig) =>
3547
})
3648

3749
const dependencies = new Set<FluidConfig>()
38-
props.setValue(rawProps, { dependencies, host })
50+
props.setValue(givenProps, { dependencies, host })
3951

4052
useLayoutEffect(() => {
4153
each(dependencies, dep => dep.addChild(props))
4254
return () => each(dependencies, dep => dep.removeChild(props))
4355
})
4456

45-
return (
46-
<Component
47-
{...host.getComponentProps(props.getValue()!)}
48-
ref={
49-
hasInstance &&
50-
((value: any) => {
51-
instanceRef.current = updateRef(ref, value)
52-
})
53-
}
54-
/>
55-
)
57+
const usedProps = host.getComponentProps(props.getValue()!)
58+
return <Component {...usedProps} ref={ref} />
5659
})
60+
}
5761

5862
function updateRef<T>(ref: Ref<T>, value: T) {
5963
if (ref) {

0 commit comments

Comments
 (0)