Conversation
|
Thanks for the PR! |
|
Actually there's one concern – if someone uses |
|
|
||
| const component = render(<TestComponent />); | ||
| const view = component.getByTestId('AnimatedView'); | ||
| expect(view.props.style[0].opacity).toBe(0); |
There was a problem hiding this comment.
Could you use the renderHook function to test the useTimestamp hook? It will be cleaner and simpler than the use of helper components. For example, here, you could simply do:
test('initializes to 0', () => {
const { result } = renderHook(() => useTimestamp(false));
expect(result.current.value).toBe(0);
});|
It would be better if there would be at most one shared value (or mutable value) that is shared between all instances of this hook. @tomekzaw I'm curious how you'd want to solve this? If we share frame callbacks across component instances, then we would not be able to share their active states. We would need some kind of update filtering. How lightweight would we want to keep this? |
I think ideally with a lazy initialization: the file in top-level could describe e.g. |
|
@ashfurrow @tjzel Yes, exactly. There should be one global mutable value. Side-note: A better version of this would be that developers call We enable the frame callback when the number of mounted The only concern here is regarding the components frozen with react-freeze, I'm not sure how this will behave. In such case we could just return some mock of a mutable value with a constant value to prevent updates while the component is frozen. What do you think? |
Are we sure? The current timestamps update based on their start time, and can be paused individually. I agree that developers are better off with a single hook instead of 100, but if we try to make that optimization for them we constrain what the API can do.
Yes I agree – it's better to leave app architecture up to developers. They can use context if they really want to. |
|
I've simplified the tests, thanks for the feedback. I chatted further with Tomasz and decided to add a warning to discourage developers from over-using this. This avoids having the library make opinionated decisions about app architecture, but we can iterate on the API too. |
tjzel
left a comment
There was a problem hiding this comment.
Could you also add a docs page for this new API? Could be in a follow-up PR.
| const frameCallback = useFrameCallback((info) => { | ||
| 'worklet'; | ||
| timestamp.value = info.timeSinceFirstFrame; | ||
| }, isActive); |
There was a problem hiding this comment.
nit
| const frameCallback = useFrameCallback((info) => { | |
| 'worklet'; | |
| timestamp.value = info.timeSinceFirstFrame; | |
| }, isActive); | |
| const frameCallback = useFrameCallback(({timeSinceFirstFrame) => { | |
| 'worklet'; | |
| timestamp.value = timeSinceFirstFrame; | |
| }, isActive); |
| * Lets you run a function on every frame update. This is expensive, so don't | ||
| * create multiple timers if you can use one and share it. |
There was a problem hiding this comment.
I think this was supposed to be in useTimestamp.ts
Also, maybe something less threatening:
| * Lets you run a function on every frame update. This is expensive, so don't | |
| * create multiple timers if you can use one and share it. | |
| * Lets you run a function on every frame update. | |
| * | |
| * For best performance, prefer to re-use a single `useTimestamp` timer instead of creating multiple ones. |
| import { useSharedValue } from './useSharedValue'; | ||
|
|
||
| /** | ||
| * Lets you access the current frame timestamp as a shared value. |
There was a problem hiding this comment.
Could you also add an inline link there?
| * Lets you access the current frame timestamp as a shared value. | |
| * Lets you access the current frame timestamp as a Shared Value. |
There was a problem hiding this comment.
This test suite has no value as it only tests the mock implementation. useFrameCallback. I added tests for useFrameCallback in #9255. After it's merged you can add a test that checks if the .value is actually progressed across frames.
Summary
When driving animations or shaders based on the current time, I had to use this kind of code locally. It adds a bit of complexity to a component that already had a lot of complexity, and it was suggested to me that others could benefit from this.
The code accepts an
isActiveparameter which you could change based on your react-navigation focus state, for example. This pauses the animations while they're off screen.Test plan
Equivalent code is working in production for me (I didn't patch the library, but I'm using the same calls). I also added thorough unit tests.