svelte icon indicating copy to clipboard operation
svelte copied to clipboard

feat: add `onAnimationFrame` lifecycle function

Open Rich-Harris opened this issue 11 months ago • 13 comments

Just an idle thought I had while washing the dishes: should we have an onFrame function? It would mean for example that this demo could be written like this:

$effect(() => {
  const context = canvas.getContext('2d');

  onFrame(() => {
    paint(context, Date.now());
  });
});

Alternatively we might want to have some sort of reactive time primitive (other than SvelteDate) so that it could be used in deriveds too. Either way not wedded to it, just an idle thought that I thought was worth a PR

Before submitting the PR, please make sure you do the following

  • [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • [x] Prefix your PR title with feat:, fix:, chore:, or docs:.
  • [x] This message body should clearly illustrate what problems it solves.
  • [ ] Ideally, include a test that fails without this PR but passes with it.
  • [x] If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • [x] Run the tests with pnpm test and lint the project with pnpm lint

Rich-Harris avatar Dec 06 '24 20:12 Rich-Harris

🦋 Changeset detected

Latest commit: 605a1f732cf9a1c8f3bdedb8cd7c0f57b2cb2b26

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

changeset-bot[bot] avatar Dec 06 '24 20:12 changeset-bot[bot]

preview: https://svelte-dev-git-preview-svelte-14594-svelte.vercel.app/

this is an automated message

Rich-Harris avatar Dec 06 '24 20:12 Rich-Harris

Playground

pnpm add https://pkg.pr.new/svelte@14594

github-actions[bot] avatar Dec 06 '24 20:12 github-actions[bot]

Playground

pnpm add https://pkg.pr.new/svelte@14594

github-actions[bot] avatar Dec 06 '24 20:12 github-actions[bot]

While it's nice, this does feel more of a thing for a utility or animation library. I wouldn't call it a lifecycle function at least and expose it through svelte/reactivity instead.

dummdidumm avatar Dec 06 '24 21:12 dummdidumm

Adjacent to #12441

ottomated avatar Dec 08 '24 08:12 ottomated

Adjacent to #12441

I'm not sure it is at all. You definitely don't want to be updating the UI with Date.now() every frame, that's going to put a lot of pressure on the runtime for no real benefit. I'd imagine you'd only want to update the time in relation to your UI requirements, such as every second or minute. This is very much a user-space problem rather than a problem that Svelte should even attempt to solve.

trueadm avatar Dec 12 '24 00:12 trueadm

Preview: https://svelte-dev-git-preview-svelte-14594-svelte.vercel.app/

svelte-docs-bot[bot] avatar Apr 12 '25 01:04 svelte-docs-bot[bot]

Renamed to onAnimationFrame. I toyed with putting it in svelte/reactivity or svelte/motion but neither felt right — I think you can make the case that it is a lifecycle function, and it definitely feels more natural to me to have it alongside onMount than elsewhere

Rich-Harris avatar Apr 12 '25 01:04 Rich-Harris

FWIW I still think this is not worth adding as it's so easy to replicate in user land - so if this is about cleaning the PR queue I'd rather close it.

dummdidumm avatar Apr 14 '25 11:04 dummdidumm

It's easy but annoying — you have to understand whether it's 'safe' to run the logic inside a requestAnimationFrame callback the first time or if it'll result in flicker unless you call it directly inside the effect, in which case you might need to faff about with untrack unless you're using onMount (you don't need to, because it is safe, but that means you have to call requestAnimationFrame twice — once inside the callback, once to kick it off). And of course it's a lot more verbose — this...

$effect(() => {
  let frame = requestAnimationFrame(function next() {
    frame = requestAnimationFrame(next);
    do_stuff();
  });

  return () => {
    cancelAnimationFrame(frame);
  };
});

...versus this:

import { onAnimationFrame } from 'svelte';

onAnimationFrame(() => {
  do_stuff();
});

The intent-to-noise ratio is much higher in the second case. It's something I've wanted often enough that I do think its presence is justified, it's not just about cleaning the PR queue.

Rich-Harris avatar Apr 14 '25 13:04 Rich-Harris

I'm not saying it doesn't have any value, but not that it deserves to be in the same place as things like "real" life cycle hooks or other important stuff under the svelte import space. It feels like something that can be put into a 3rd party lib like runed

dummdidumm avatar Apr 14 '25 13:04 dummdidumm

I'm not saying it doesn't have any value, but not that it deserves to be in the same place as things like "real" life cycle hooks or other important stuff under the svelte import space. It feels like something that can be put into a 3rd party lib like runed

We have something similar in runed :) https://www.runed.dev/docs/utilities/animation-frames

TGlide avatar May 20 '25 21:05 TGlide