Skip to content

Commit da8ec49

Browse files
committed
feat: add "key" prop
This lets users pass immutable objects as items
1 parent a9569b4 commit da8ec49

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

packages/core/src/useTransition.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ export function useTransition<T>(
2020
props: any,
2121
deps?: any
2222
) {
23-
const { ref, reset, trail = 0, expires = Infinity } = props
23+
const { key, ref, reset, trail = 0, expires = Infinity } = props
2424

2525
// Every item has its own transition.
2626
const items = toArray(data)
2727
const transitions: Transition[] = []
2828

29+
// Explicit keys are used to associate transitions with immutable items.
30+
const keys = is.und(key) ? key : is.fun(key) ? items.map(key) : toArray(key)
31+
2932
// The "onRest" callbacks need a ref to the latest transitions.
3033
const usedTransitions = useRef<Transition[] | null>(null)
3134
const prevTransitions = usedTransitions.current
@@ -38,25 +41,25 @@ export function useTransition<T>(
3841
usedTransitions.current!.forEach(t => t.spring.destroy())
3942
})
4043

41-
// Determine which items are new.
42-
let newItems = items
43-
if (prevTransitions && !reset) {
44-
// Reuse old transitions unless expired.
44+
// Determine which transitions can be reused.
45+
const prevKeys: any[] = []
46+
if (prevTransitions && !reset)
4547
prevTransitions.forEach(t => {
4648
if (is.und(t.expiresBy)) {
49+
prevKeys.push(keys ? t.key : t.item)
4750
transitions.push(t)
4851
} else {
4952
clearTimeout(t.expirationId)
5053
}
5154
})
52-
const oldItems = transitions.map(t => t.item)
53-
newItems = newItems.filter(item => oldItems.indexOf(item) < 0)
54-
}
5555

5656
// Append new transitions for new items.
57-
newItems.forEach(item => {
58-
const spring = new Controller()
59-
transitions.push({ id: spring.id, item, phase: Phase.Mount, spring })
57+
items.forEach((item, i) => {
58+
const key = keys && keys[i]
59+
if (prevKeys.indexOf(keys ? key : item) < 0) {
60+
const spring = new Controller()
61+
transitions.push({ id: spring.id, key, item, phase: MOUNT, spring })
62+
}
6063
})
6164

6265
// Track cumulative delay for the "trail" prop.
@@ -81,7 +84,7 @@ export function useTransition<T>(
8184
from = props.from
8285
}
8386
} else {
84-
const isDeleted = items.indexOf(t.item) < 0
87+
const isDeleted = (keys || items).indexOf(keys ? t.key : t.item) < 0
8588
if (t.phase < LEAVE) {
8689
if (isDeleted) {
8790
to = props.leave
@@ -185,6 +188,7 @@ interface Change {
185188

186189
interface Transition<T = any> {
187190
id: number
191+
key?: keyof any
188192
item: T
189193
phase: Phase
190194
spring: Controller

0 commit comments

Comments
 (0)