npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@fernandorojo/react-native-shared-animation

v1.0.1

Published

A nimble global animtion-state management tool for react-native's `Animated` values. Think of it like a simple redux for react-native animation values.

Downloads

5

Readme

🕺 react-native-shared-animation

A global animation-state management tool for react-native's Animated values. Think of it like a simple redux for react-native animation values.

This package is super easy to use and requires no more than 1 minute of learning.

Also supports react-native-reanimated and react-native-gesture-handler.

Why?

Sharing animated values across components should be easy. However, it currently requires so much prop drilling that any complex animation in react-native becomes a hassle to manage.

🤔 When might you use this?

Any time you find yourself passing a certain animation value from one component to another more than once, react-native-shared-animation feels like a breath of fresh air.

Example use case

Maybe you have a component with a ScrollView, and a header you want to react to its scroll position, but the two components aren't that close together code-wise. If this were the case, without this library, have to declare an animated value high up in the component tree, and then pass it down the three through many layers of components.

This library aims to fix that.

I also think this could help make it easy to achieve shared transitions across screens. I haven't put together an example for that yet, so if you do, please submit a PR :)

Syntax

Much of the syntax is similar to react-redux, but if you aren't familiar with how redux works, don't worry; this is much simpler.

Quick setup

The boilerplate setup takes about 15 seconds and is similar to redux in how it works. Just wrap your entire app with the <SharedAnimationProvider /> component.

App.js

import React from 'react'
import { SharedAnimationProvider } from 'react-native-shared-animation'
import Animated from 'react-native-reanimated'
import App from './src/App'

export default () => {
	const animatedValues = { myCoolAnimatedValue: new Animated.Value(0) }
	return (
		<SharedAnimationProvider animatedValues={animatedValues}>
			<App />
		</SharedAnimationProvider>
	)
}

In some other nested component, all you'd need to do is this:

import React from 'react'
import { useSharedAnimation } from 'react-native-shared-animation'
import Animated from 'react-native-reanimated'

export default () => {
	// here we get the value from our global store using react hooks
	const { getValue } = useSharedAnimation();
	const coolValue = getValue('myCoolAnimatedValue');
	
	return <Animated.View style={{ width: coolValue }} />
}

You can also use the connectSharedAnimation HOC or the <SharedAnimation /> component if you don't want to use the useSharedAnimation hook.

🎉 All set. Your app is now ready to share animated values across components.

Below I'll expand on all the ways that you're able to 1) initialize animated values and 2) access animated values.

Examples

To see full examples, go to the /examples folder. You can also see the Expo snack of examples here.

Installation

To install, open your react native repository in the terminal and run this command:

npm i react-native-shared-animation

You could use yarn if you prefer that:

yarn react-native-shared-animation

Recommended: If you want to use react-native-reanimated for animations, run this afterwards:

npm i react-native-reanimated react-native-gesture-handler

This works with...

react-native-reanimated

Animated from react-native if you prefer that.

Expo

Typescript

react-native-gesture-handler

1) Initializing shared animated values

You have two options for initializing shared animation values: global initialization or on-the-fly initializiation in components.

i) [Recommended] Initialize global animated values

Simply pass an animatedValues object as a prop to the <SharedAnimationProvider /> component. This will act as the initial set of animated values.

You can initialize as many animated values as you'd like.

App.js

import React from 'react'
import { SharedAnimationProvider } from 'react-native-shared-animation'
import Animated from 'react-native-reanimated'
import App from './src/App' // path to your root component

export default () => {
	const mainScrollValue = new Animated.Value(0)
	const animatedValues = { mainScrollValue }
	
	<SharedAnimationProvider animatedValues={animatedValues}>
		<App />
	</SharedAnimationProvider>
}

🐻 That's it! Your app now has globally-accessible animated values.

In this case, mainScrollValue can be accessed by any component.

If you come from a redux background, you can think of this like setting the initial store value.

Why this is the better option:

From a style perspective, it is useful to know what values will be accessible across your app upon initialization. And when it comes to performance, this is less prone to bugs, since you'll never try to access a value that hasn't been initialized.

That said, you also have the newValue method to your disposal, as described in the next option.

ii) [Careful] Initialize animated values on the fly in components

You can also initialize animated values directly in components. The thing is, this option is more prone to bugs, since you might try to access an animated value before it's been initialized.

Overall, I'd suggest only using this one on a case-by-case basis.

It can be achieved with the newValue(name, value) function, documented below.

2) Accessing animated values

Here's the fun part.


There are 3 ways to access animated values

These are the 3 options you have:

  1. useSharedAnimation hook: The useSharedAnimation hook is super simple (and is my favorite to use). Only works in function components. See react hooks to learn more.

  2. connectSharedAnimation HOC: You can use the connectSharedAnimation higher-order component. Useful for class components and function components. Good for taking animation logic out of a component, too.

  3. SharedAnimation component: You can also wrap any component with <SharedAnimation /> to connect it to the global animation state.


Option 1: useSharedAnimation

Call useSharedAnimation in the root of a function component.

Example:

...
import { useSharedAnimation } from 'react-native-shared-animation'

export default () => {
	const { getValue, newValue, animatedValues } = useSharedAnimation();
	const scroll = getValue('scroll')
	// same as...
	const { scroll } = animatedValues;
	
	return <Animated.View style={{ ..., translateX: scroll }} />
}

So simple!

🤑🤑

If you're using a version of react / react-native that supports hooks, you can happily stop reading the docs here and just use this.

--

Option 2: connectSharedAnimation(mapValuesToProps)(Component)

You can also use the connectSharedAnimation higher-order component to pass animated values as props.

This option gives you some customization options beyond the useSharedAnimation, such as taking global animated code out of your actual component.

This HOC passes newValue, getValue, and any animated values you choose as props to your Component.

Example:

...
import { connectSharedAnimation } from 'react-native-shared-animation'

const ConnectedComponent = ({ getValue, newValue, scroll }) => {
	return <Animated.View style={{ ..., translateX: scroll }} />
}

// determine which values you want to pass to this component
const mapValuesToProps = animatedValues => ({
	scroll: animatedValues.scroll
})

// could also have done this:
// const mapValuesToProps = 'scroll'

// ...or this:
// const mapValuesToProps = ['scroll', 'someOtherValue']

export default connectSharedAnimation(mapValuesToProps)(ConnectedComponent)

mapValuesToProps (required)

This is the first and only argument for connectSharedAnimation. It determines which animated values will be passed to the component as direct props.

This value can be either a string, array of strings, a function, or null.

mapValuesToProps as a string

The string should correspond to an existing global animated value.

...
import { connectSharedAnimation } from 'react-native-shared-animation'

const ConnectedComponent = ({ getValue, newValue, scroll }) => {
	return <Animated.View style={{ ..., translateX: scroll }} />
}

const mapValuesToProps = 'scroll'

export default connectSharedAnimation(mapValuesToProps)(ConnectedComponent)

mapValuesToProps as an array of strings

Enter the names of multiple global animated values you want passed as direct props.

...
import { connectSharedAnimation } from 'react-native-shared-animation'

const ConnectedComponent = ({ getValue, newValue, scroll, someOtherValue }) => {
	return <Animated.View style={{ ..., translateX: scroll }} />
}

// const mapValuesToProps = ['scroll', 'someOtherValue']

export default connectSharedAnimation(mapValuesToProps)(ConnectedComponent)

mapValuesToProps a function

A function that takes in animatedValues as its first argument and returns an object that references these values. This can be useful if you want to abstract some animation logic out of your component.

...
import { connectSharedAnimation } from 'react-native-shared-animation'

const ConnectedComponent = ({ getValue, newValue, scroll, opacity }) => {
	return <Animated.View style={{ ..., translateX: scroll }} />
}

const mapValuesToProps = animatedValues => {
	const { scroll } = animatedValues;
	const opacity = interpolate(scroll, {
		inputRange: [0, 400],
		outputRange: [1, 0]
	})
	return {
		scroll,
		opacity
	}
}

export default connectSharedAnimation(mapValuesToProps)(ConnectedComponent)

The function works the same as redux's mapStateToProps.

mapStateToValues as null

You can pass null to it if you don't want any animated values explicitly passed to the component. If you pass null, you will still have access to getValue and newValue.

Option 3: SharedAnimation Component

A basic component that uses the render props method. (Similar in principle to the [Query]() component from react-apollo.)

...
import { SharedAnimation } from 'react-native-shared-animation'

export default () => {
	return (
		<SharedAnimation>
			{({ getValue, newValue }) => {
				const scroll = getValue('scroll')
				return (
					<YourComponent scroll={scroll} />
				)
			})}
		</SharedAnimation>
	)
}

getValue(name)

A function that takes in the name of a global animated value and returns the animated value itself.

This is the most important function that you'll find yourself using all the time.

Example

const SomeComponent = () => {
	const { getValue } = useSharedAnimation()
	
	const opacity = getValue('opacity')
	
	return (
		<Animated.View style={{ opacity }} />
	)
}

animatedValues

A dictionary containing the current global state of animated values. You can use this to access the global store directly, but I recommend using getValue instead, since it has some added convenience checks.

Example

const SomeComponent = () => {
	const { animatedValues } = useSharedAnimation()
	
	const { opacity } = animatedValues
	
	return (
		<Animated.View style={{ opacity }} />
	)
}

newValue(name, value)

A function that creates a new global animated value. Takes a name as the first argument, and an animated value (or node) as the second argument.

Returns: the animated value it just created

Example

const SomeComponent = () => {
	const { newValue } = useSharedAnimation();
	
	const opacity = newValue('opacity', new Animated.Value(1))
	
	return (
		<Animated.View style={{ opacity }} />
	)
}

Documentation Recap

<SharedAnimationProvider />

| Prop | Required | Type | Example | |---|---|---|---| | animatedValues | no (but recommended) | dictionary | { scroll: new Animated.Value(0) } | | children | yes | React.Node | Your app JSX should be a child component of this provider. |

Illustrative example

Sharing animated values across your entire app is as easy as this:

import React from 'react'
import Animated from 'react-native-reanimated'
import { SharedAnimationProvider, useSharedAnimation} from 'react-native-shared-animation'

export default function App() {
	const animatedValues = { scroll: new Animated.Value(0) }
	return (
		<SharedAnimationProvider animatedValues={animatedValues}>
			<ComponentWithScrollView />
			<OtherComponentThatAccessesScroll />
		</SharedAnimationProvider>
	)
}

const OtherComponentThatAccessesScroll = () => {
	const { getValue } = useSharedAnimation()
	const scroll = getValue('scroll')
	
	return <Animated.View style={{ translateX: scroll }} />
}

const ComponentWithScrollView = () => {
	const { getValue } = useSharedAnimation()
	const scroll = getValue('scroll')
	const onScroll = Animated.event([
		{
			nativeEvent: {
				contentOffset: {
					y: scroll
				}
			}
		}
	])

	return (
		<Animated.ScrollView onScroll={onScroll} />
	)

}

Yup, that's it. No prop drilling at all.