question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: `useImperativeGetter`

See original GitHub issue

I wanted to read an animated value on the JS thread, because I wanted to persist that value to an AsyncStorage so I could use it later.


I learned that I can use call (thanks to your comment here) to get the current value, but of course I have to wrap it in <Animated.Code> or useCode and I also have to do some extra things if I want the value ‘just once’.


In the end I made this masterpiece of a hook which I am very proud of:

import React, {useReducer, Reducer} from 'react';
import Animated, {useCode, cond, call} from 'react-native-reanimated';

type AddListenerAction<T> = {
	type: 'add-listener';
	resolveFn: (num: T) => void;
};

type RemoveListenerAction<T> = {
	type: 'resolve';
	value: T;
};

type State<T> = {
	inProgress: number;
	resolveFns: ((num: T) => void)[];
};

export const useImperativeGetter = <T,>(
	value: Animated.Node<T>
): (() => Promise<T>) => {
	const [s, dispatch] = useReducer<
		Reducer<State<T>, AddListenerAction<T> | RemoveListenerAction<T>>
	>(
		(state, action) => {
			switch (action.type) {
				case 'add-listener':
					return {
						inProgress: 1,
						resolveFns: [...state.resolveFns, action.resolveFn]
					};
				case 'resolve':
					return {
						inProgress: 0,
						resolveFns: []
					};
				default:
					return state;
			}
		},
		{
			inProgress: 0,
			resolveFns: []
		}
	);
	const callback = React.useCallback(
		v => {
			dispatch({
				type: 'resolve',
				value: v[0]
			});
			for (const fn of s.resolveFns) {
				fn(v[0]);
			}
		},
		[s.resolveFns]
	);
	useCode(() => cond(s.inProgress, call([value], callback)), [
		s.inProgress,
		value
	]);

	return () =>
		new Promise<T>(resolve => {
			dispatch({
				type: 'add-listener',
				resolveFn: resolve
			});
		});
};

This is how it’s used:

const value = new Animated.Value(0)
const getValue = useImperativeGetter(value)

now anywhere in your code you can call the returned function to get the current value.

await getValue()
// => 0

I took special care of avoiding concurrency issues or race conditions. So for example you can call it multiple times Promise.all([getValue(), getValue(), getValue()]) and you should get [0, 0, 0]. Hence why it uses useReducer, to batch multiple state updates at once.

Would you like to include this in your library? Is this even a smart thing to do or is there already some easier way to do it in the ecosystem? Would love to hear your opionions.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:12 (12 by maintainers)

github_iconTop GitHub Comments

1reaction
JonnyBurgercommented, Oct 19, 2020

So I don’t need it needs to be included anymore 😃 Anyone can feel free to copy my function. Closing this

1reaction
JonnyBurgercommented, Sep 29, 2020

With Reanimated 2 coming out we probably need another solution in the long term.

But I still use this function and it worked well, so I would recommend you to just copy the function into your codebase.

Read more comments on GitHub >

github_iconTop Results From Across the Web

VariableSizeGrid does not clear clear cache and ... - GitHub
The grid doesn't invalidate cached sizes when the getter methods change ... that but It's a bit sad that we have to use...
Read more >
[Review] SE-0023 API Design Guidelines - Announcements - Swift ...
Hello Swift community, The review of SE-0023"API Design Guidelines" begins now and runs through January 31, 2016. The proposal is available here: ...
Read more >
CS 3110 Lecture 16 Mutable data abstractions
Programmers in object-oriented languages often define operations that are getters and setters, allowing reads from and writes to fields of an object.
Read more >
Hooks API Reference - React
Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. This page...
Read more >
Designing a decision service using DRL rules
If you need to use imperative or conditional code in rule actions, then divide the rule into multiple smaller and more declarative rules....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found