Skip to content

Commit

Permalink
sample
Browse files Browse the repository at this point in the history
  • Loading branch information
nandorojo committed Feb 20, 2024
1 parent 7a00abc commit aa49042
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 24 deletions.
2 changes: 1 addition & 1 deletion examples/sample/App.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from './src/Moti.Skeleton'
export { default } from './src/Perf.List'
115 changes: 115 additions & 0 deletions examples/sample/src/Perf.List.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { useMotify } from 'moti'
import { useEffect, useReducer, useState } from 'react'
import { Button, View, ViewStyle } from 'react-native'
import Animated, { useAnimatedStyle } from 'react-native-reanimated'

global.shouldDebugMoti = false

const modes = ['Animated', 'Moti'] as const

let logs: Record<string, number[]> = {}

const list = new Array(1).fill(null).map((_, i) => i)

export default function List() {
const [mode, setMode] = useState<(typeof modes)[number]>(modes[0])
const [, render] = useReducer((s) => s + 1, 0)

let renderStartAt = Date.now()

useEffect(() => {
const interval = setInterval(() => {
render()

const maxRendersPerMode = 4

if (logs[mode]?.length === maxRendersPerMode) {
// remove biggest and smallest values
clearInterval(interval)
const nextMode = modes[modes.indexOf(mode) + 1]

if (nextMode) {
setMode(nextMode)
} else {
console.log(logs)

let means = {}
let medians = {}

for (let key in logs) {
means[key] = logs[key].reduce((a, b) => a + b, 0) / logs[key].length
}

for (let key in logs) {
const list = logs[key].slice().sort()
medians[key] = list[list.length / 2] ?? list[(list.length - 1) / 2]
}

console.log('Averages: ', JSON.stringify(means, null, 2))

console.log('Medians: ', JSON.stringify(medians, null, 2))

logs = {}
}
}
}, 600)

return () => {
clearInterval(interval)
}
}, [mode])

useEffect(
function measurePerf() {
let renderEndAt = Date.now()

const duration = renderEndAt - renderStartAt

logs[mode] = logs[mode] || []
logs[mode].push(duration)
},
[mode, renderStartAt]
)

return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}}
>
{modes.map((m) => (
<Button
key={m}
title={m}
onPress={() => {
setMode(m)
render()
}}
/>
))}

<Lists mode={mode} key={Math.random()} />
</View>
)
}

const Lists = ({ mode }) => {
return (
<>
<>{mode === 'Animated' && list.map((_, i) => <Reanimated key={i} />)}</>
<>{mode === 'Moti' && list.map((_, i) => <Moti key={i} />)}</>
</>
)
}
const Reanimated = () => {
return (
<Animated.View style={useAnimatedStyle(() => ({}), [])}></Animated.View>
)
}

const Moti = () => {
const { style } = useMotify<ViewStyle>({})
return <Animated.View style={style}></Animated.View>
}
26 changes: 25 additions & 1 deletion examples/sample/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
{
"compilerOptions": {},
"compilerOptions": {
"paths": {
"moti": ["../../packages/moti/src"]
},
"composite": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react-jsx",
"lib": ["esnext", "dom"],
"module": "esnext",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
"noStrictGenericChecks": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext",
"noImplicitAny": false
},
"extends": "expo/tsconfig.base"
}
45 changes: 24 additions & 21 deletions packages/moti/src/core/use-motify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type {
PresenceContext,
usePresence as useFramerPresence,
} from 'framer-motion'
import { useCallback, useEffect } from 'react'
import { useCallback, useEffect, useMemo } from 'react'
import type { TransformsStyle } from 'react-native'
import {
useAnimatedStyle,
Expand Down Expand Up @@ -339,20 +339,23 @@ export function useMotify<Animate>({

const disableInitialAnimation =
presenceContext?.initial === false && !animateInitialState
const custom = useCallback(() => {
'worklet'
return presenceContext?.custom
}, [presenceContext])

const reanimatedSafeToUnmount = useCallback(() => {
safeToUnmount?.()
}, [safeToUnmount])

const reanimatedOnDidAnimated = useCallback<NonNullable<typeof onDidAnimate>>(
(...args) => {
onDidAnimate?.(...args)
},
[onDidAnimate]

const { custom, reanimatedSafeToUnmount, reanimatedOnDidAnimate } = useMemo(
() => ({
custom: () => {
'worklet'
return presenceContext?.custom
},
reanimatedSafeToUnmount: () => {
safeToUnmount?.()
},
reanimatedOnDidAnimate: (
...args: Parameters<NonNullable<typeof onDidAnimate>>
) => {
onDidAnimate?.(...args)
},
}),
[onDidAnimate, presenceContext, safeToUnmount]
)

const hasExitStyle = Boolean(
Expand Down Expand Up @@ -468,7 +471,7 @@ export function useMotify<Animate>({
}
) => void = (completed = false, recentValue, info) => {
if (onDidAnimate) {
runOnJS(reanimatedOnDidAnimated as any)(
runOnJS(reanimatedOnDidAnimate as any)(
key as any,
completed,
recentValue,
Expand Down Expand Up @@ -666,19 +669,19 @@ export function useMotify<Animate>({
isMounted,
isPresent,
onDidAnimate,
reanimatedOnDidAnimated,
reanimatedOnDidAnimate,
reanimatedSafeToUnmount,
state,
stylePriority,
transitionProp,
])

useEffect(() => {
isMounted.value = true
}, [isMounted])

useEffect(
function allowUnMountIfMissingExit() {
if (fromProp && isMounted.value === false) {
// put this here just to avoid having another useEffect
isMounted.value = true
}
if (!isPresent && !hasExitStyle) {
reanimatedSafeToUnmount()
}
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@
"target": "esnext",
"noImplicitAny": false
},
"exclude": ["examples"]
"exclude": ["./examples"]
}

0 comments on commit aa49042

Please sign in to comment.