Unable to add class to each element?

Don’t know what I’m doing wrong here. I am trying to create a function in React to iterate over a string you pass through, then add an animation class to each element, while also upping the animation delay by .1s every letter. This is what I have currently and am unable to add the class as it comes back with undefined??

const useAnimationClass = () => ({
  fade: {
    animation: 'shinyName .1s infinite',
    animationDelay: '1s',
    animationDuration: '7s',
  },
})

const classes = useAnimationClass();

const colorFade = (str) => {
  let splitLetters = str.split('')

  splitLetters.forEach((ltr, idx) => {
    console.log(ltr, idx)
    ltr[idx].classList.add(classes.fade)
  })
  // let spans = []
  // for (let i = 0; i < str.length; i++) {
  //   spans.push(<span key={i}>{str[i]}</span>)
  // }
  // return spans
}

console.log(colorFade('TestString'))

EDIT: Just realizing now I have to probably split the letters, add them into a span, then add the class to each span.

Yeah, that would be a better idea.

I’m not really understand why are you doing this outside react, though? You can just map through every character in your component, aren’t you?

1 Like

Confused by this. I don’t know what you mean outside of React. I’m trying to map currently and maybe to a string interpolation on the delay like so, but delay is undefined:

const useAnimationClass = (delay) => ({
  fade: {
    animation: 'shinyName .1s infinite',
    animationDelay: `${delay}`,
    animationDuration: '7s',
  },
})

const classes = useAnimationClass();

const colorFade = (str) => {
  let delay = classes.fade.animationDelay
  let splitLetters = str.split('')

  splitLetters.map((ltr, idx) => {
    console.log(delay)
    console.log(<span className={classes.fade} key={idx}>{ltr}</span>)
  })
}

console.log(colorFade('TestString'))

Just added delay = '1s' as the parameter, so that works.

Why not inside component?

const AnimatedString = ({ string }) => (
  <>
    { [...string]
      .map((letter, index) => (
        <span className="animated-string" style={{ animationDelay: `.${index + 1}s`}}>
          {letter}
        </span>
      )) }
  </>
);

UPDATE: Fixed typos

1 Like

Ohh, I don’t know. I suppose I’m not a bright one, hahaha

There isn’t any point in useAnimationClass being a function, you look like you’re overabstracting here

Simplest way here is make a component that takes an array of letters and returns a mapping to a span for each. Then set style={{animationDelay: whateverTheDelayIs * index}} on each span

letters.map((letter, i) => <span style= ....

Edit: yep same thoughts as @snigo here

Nono, don’t think that – there are specific patterns to use when coding React apps that make life easier. But it’s easy to code yourself into a hole when you get an idea stuck in your head and you think you know how it should work and then completely bypass those patterns or forget about them

2 Likes

This doesn’t work on it’s own as a component? Getting linting issues?

import React from 'react'

const AnimatedString = ({ string }) => (
  <>
    { [...string]
      .map((letter, index) => (
        <span className="animated-string" style={{ animationDelay: `.${index + 1}s`}}>
          {letter}
        </span>
      )
  </>
)

No closing curly bracket

1 Like

Cool, got it. Thanks!

So currently, if I pass a string into it, the delay is never updated with + .1s. Any ideas?

It works for me: https://codepen.io/snigo/full/XWJvzWG

1 Like

This is how I had to solve it, it wasn’t accepting animationDelay?

import React from 'react'

const ColorString = ({ string }) => (
  <>
    {
      [...string]
        .map((letter, index) => (
          <span
            key={index}
            idx={index}
            style={{ 
              animation: `shinyName .1s .${index + 1}s infinite`,
              animationDuration: '7s',
            }}
          >
            {letter}
          </span>
        ))
    }
  </>
)

export default ColorString

I see the difference now. Thank you guys very very much.

No problem! Just keep in mind that wrapping each letter of the string in animated span is quite a heavy load for browser. It’s absolutely fine if it’s the only element on the page, like splash screen or something, but if page has a lot of stuff it might be overkill :wink:

Is it really? Oh geez. I didn’t think it’d be so rough on the browser. It just doesn’t seem like such a heavy thing to be loaded, you know?