Jump to content
Search Community

Stars Background - A Performance Dissertation (w/ React)

emmme test
Moderator Tag

Recommended Posts

Hi,

 

When it comes to performance and optimization, there is an argument to be made about everything. Whether or not making such argument makes sense or is worth making it, that's an entirely different thing. When it comes to performance is always a good idea to test, test, test. If you see something that is not working then try a different approach.

 

Blake's approach is great and should work really nice regardless of the UI framework you use (React, Vue, Svelte, Alpine, etc). Just be sure that you append the fragment to an element that will be removed when the route changes (the view is unmounted) or manually do so in the cleanup phase of the effect hooks.

 

As for specific React performance issues, normally those could arise in this cases because you are tying something to the state in order to create the elements, updating some state property constantly (causing a bunch of re-renders). Other than that any performance problem will happen regardless of the framework (if you are using one).

 

Is using a document fragment in React something that can be done? Sure why not. Again if you are careful about it it shouldn't cause any issues. Maybe some React purists will consider you a blasphemous, but those are React purists being React purists (see the first paragraph and instead of performance use react best practices) 🤷‍♂️

 

Finally you are using GSAP Context in your effect hook but you are not reverting it in the cleanup phase of your effect hook:

useLayoutEffect(() => {
  const ctx = gsap.context(() => {});
  
  return () => ctx.revert(); // <- easy cleanup!
}, []);

Take a look at the resources we have in this page:

 

Hopefully this helps.

Happy Tweening!

  • Like 2
Link to comment
Share on other sites

@Rodrigo  i forgot about reverting the context..! I have it in my VsCode snippet, must have written it by scratch and forgot....

 

6 hours ago, Rodrigo said:

but those are React purists being React purists (see the first paragraph and instead of performance use react best practices) 🤷‍♂️

haha indeed, call it in "NorthPolean" or call it in "SouthPolean" still ice it is

 

I updated the codesanbox in order to include

•Reverting

•Fragment / adding each star to the fragment

https://codesandbox.io/p/sandbox/nifty-voice-gnkw7w?file=%2Fsrc%2Fpages%2FHome%2Findex.jsx%3A15%2C20

but i can't make the stars appear... 

Link to comment
Share on other sites

Hi,

 

Sorry for the late response 🙏

 

The main issue is that you are adding your fragment and creating references to DOM nodes that are not yet rendered:

var frag = document.createDocumentFragment();
var app = document.querySelector(".star-background");
var baseStar = document.querySelector(".star");
app.appendChild(frag);

useLayoutEffect(() => {}, []);

return (
  // now the HTML is rendered
);

So app and baseStar are both null because those elements are not rendered in the DOM yet, always do anything that has to do with selectors inside an effect hook:

useLayoutEffect(() => {
  var frag = document.createDocumentFragment();
  var app = document.querySelector(".star-background");
  var baseStar = document.querySelector(".star");
  app.appendChild(frag);
}, []);

return (
  // now the HTML is rendered
);

Now adding stuff using appendChild in React could backfire if you're not careful, is better to conditionally render the element based on some state condition that you can update in your initial render, like an effect hook with an empty dependencies array and then in another effect hook that checks for that specific state property.

 

In any case this seems to work as you expect:

useLayoutEffect(() => {
  // fragment
  var app = document.querySelector(".star-background");
  var frag = document.createDocumentFragment();
  // GSAP Context
  let ctx = gsap.context((self) => {
    //Starts building
    const stars = gsap.utils.toArray(".star");
    stars.forEach((star) => {
      gsap.set(star, {
        x: () => Math.random() * window.innerWidth,
        y: () => Math.random() * window.innerHeight,
      });

      gsap.to(star, {
        duration: 1,
        opacity: 1,
        stagger: 0.2,
        repeat: -1,
        yoyo: true,
      });

      // Make the stars twinkle
      gsap.fromTo(
        star,
        {
          opacity: 0.5,
          scale: 0.5,
        },
        {
          duration: 3.5,
          delay: Math.random() * 3,
          opacity: 1,
          scale: 1,
          repeat: -1,
          yoyo: true,
          stagger: 3.2,
        },
      );
      // add star to fragment
      frag.appendChild(star);
      app.appendChild(frag);
    });
  });
  return () => ctx.revert();
}, []);

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...