For loops ever in React?

Yeah, sure, why not, it’s much easier than faffing around trying to think of how to generate IDs if you genuinely can’t just pull a unique value out of the content

Yeah, that was just an example of one of the many ways to generate IDs – I just generally use uuidV4 and be done with it for everything, as it means I don’t ever have to think about it, but then I’m normally pregenerating them & using them for lists of stuff in RN where it’s absolutely critical I don’t have needless rerenders

1 Like
import React from 'react'
import ScrollAnimation from 'react-animate-on-scroll'
import SpanMaker from '../helpers/SpanMaker'

// Styles
import "animate.css/animate.css"
import './styles/Crystal.css'
import './styles/CrystalDark.css'
import './styles/CrystalForeGround.css'

export default function Crystal() {
  const foreGroundSparkles = SpanMaker(40, i => <span key={i} />)
  const darkStripes = SpanMaker(14, i => <span key={i} />)
  const stripes = SpanMaker(19, i => <span key={i} />)

  return (
    <ScrollAnimation animateIn="fadeIn" animateOut="fadeOut" offset={100}>
      <div className="Crystal">
        <div id="foreGround">
          {foreGroundSparkles}
        </div>
        <div id="darkStripes">
          {darkStripes}
        </div>
        <div id="stripes">
          {stripes}
        </div>
      </div>
    </ScrollAnimation>
  )
}


Trying to figure out the best naming convention for this one function? You think times would be the best bet?

Naming is quite subjective, to be honest, and everybody has their own opinions.

I’d actually prefer the word times itself because it’s just a utility function, not a span maker at its core.

When I go through the code and see the times function, I understand that this is a loop that will return an array, and each value will be whatever I return from the callback function, very similar to array map function.

times function is included in Lodash, so one more reason why I personally wouldn’t rename the function itself to SpanMaker.

If I’m doing something not-so-obvious, I’d leave a comment there for my future self.

So my version will probably look something like this:

// ...
import { times } from '../path/to/utils'
/* import { times } from 'lodash' */ // You can get it from lodash also
// ...

export default function Crystal() {
  // create array of 40 spans and divs
  const foregroundSparkles = times(40, i => <span key={i} />)
  const darkStripes = times(40, i => <div key={i} />) // Make some div soup

  // ..
}

Again, it’s subjective. But, you’ll see things done somewhat in the above way.

Just to expand on this a little bit, if I needed to create a SpanMaker component (function), I’d do it like so:

// `Spans` is just a React component
// On each iteration, it's going to run `spanProps`.
// Whatever is returned from the `spanProps`, will be used as the props for that span.
const Spans = ({ num, spanProps }) => {
  let spans = []
  
  for (let i = 0; i < num; i++) {
    spans.push(<span {...spanProps(i)}></span>)
  }
  return spans
}

// Somewhere in your code
import Spans from '../path/to/Spans'

export default function Crystal() {
  return (
    <ScrollAnimation animateIn="fadeIn" animateOut="fadeOut" offset={100}>
      <div className="Crystal">
        <div id="foreGround">
          <Spans num={40} spanProps={i => ({ key: i, onClick: () => alert('You clicked foreground span') })} />
        </div>
        <div id="darkStripes">
          <Spans num={40} spanProps={i => ({ key: i, className: 'dark-stripes' })} />
        </div>
        <div id="stripes">
          <Spans num={40} spanProps={i => ({ key: i })} />
        </div>
      </div>
    </ScrollAnimation>
  )
}

You can also see my opinions about naming and usage. Again, there are a lot of ways to skin a cat.

1 Like

Thank you so much. I’m at the point in my career where I can make most things work, but not efficiently! :stuck_out_tongue:

1 Like

So, probably don’t do this at all. This a decorative element. It doesn’t have any interactivity. What it does do it make my laptop sound like it’s taking off – you’re animating a load of DOM elements. Although CSS animations are quite efficient, you are still animating a load of DOM elements, and it’s a recipe for making the user’s computer cry.

At the very least, use an SVG, not a load of styled <span> elements. Much better would be using <canvas>, but it’s may be complicated to generate. Just a GIF would be easiest, and have the same effect. React is not what should be used here, anyway

Also the scroll effect you have makes it disappear most of the time:

Looks cool, but I would definitely consider <canvas> - I’m totally not an expert on canvas stuff, but I know there are plenty libraries, like Paper.js that make such things possible

Another “hacky” solution, and I see it increasingly more often - just make it video, put it in <video> and control playback with the scroll - it’s much easier, much more predictable and stable :wink:

Good luck!

2 Likes

The other problem here is that it only scrolls like that on safari? I think I need to get a video of this somehow. What would be my best options for this?

Cracking up by the way of making the laptop take off. Which quite honestly at 2020 I thought computers would have no problem with stuff like this? Why is it so terribly performing? The original way had just about 100 hardcoded spans which renders to the same? If they are empty spans, and CSS animations are lightweight, why is this a bomb to the computer?

And Firefox and Chrome on OSX, I hadn’t looked at in Safari. I’ve only looked at in on desktop as well, not mobile.

It’s an inherently complicated thing you’re asking the computer to do. So it doesn’t really matter a huge amount how quick your computer is.

You can have more running processes than you could, say, 10 years ago. And those processes can be more resource-intensive than 10 years ago. Your OS may allow you to, say, have some hyperpowered graphics editor like Photoshop + a browser with 10,000 tabs open + a shedload of other applications all open at the same time + a game or whatever, and you couldn’t do that 10 years ago without the system grinding to a crawl. And for browser code running in specific open tabs, more powerful GPUs and the APIs that have been creted to take advantage of them (specific types of CSS animations for example) mean more graphics-related stuff can be taken off the main thread.

But all that still doesn’t matter a huge amount, because the DOM is not designed for producing fancy graphics. It’s optimised for rendering and locating and laying out [mainly] text elements in relation to one another. Even with CSS animations that delegate to the GPU rather than the CPU (eg any colour/opacity changes and any transform functions), you are still tied to the entire pipeline for constructing and rendering the DOM. This is compunded [slightly] in your case by the fact there is a layer all the calculations have to go though on top of the DOM (React).

canvas in comparison, which is optimised for this stuff, is going to be a bitmap, so like a grid of what will be coloured pixels. The browser “knows” the size and location of the canvas, and can very, very efficiently update the colour (because that’s all it’s really doing, changing the colour of the pixels) of every cell on that grid, it doesn’t do anything else apart from that. Using a video element as @snigo says is another simple option that, as long as the video is v low-res, is fairly efficient for similar reasons.

My laptop (2018 MBP, lowest spec but still v powerful computer) has no problem rendering your graphic smoothly, but the the fans kick in almost immediately. You cannot assume that a user has a super duper computer that will breeze through running this stuff – in fact, the opposite is likely to be true, as most people use phones, and while many common phones are very powerful computers, these are still DOM animations. Even for people on laptops, the majority of those are not going to be hyper powerful things optimised for intensive graphics processing – take, for example, any Chromebook.

1 Like

Thank you so much for the great answer!