Search code examples
reactjsreact-hooksrefreact-functional-component

Array of Refs in functional component to change classnames of individual items via classList


I'm converting my jQuery based project to react and run into an issue with refs in a functional component: I have a huge wordlist and each word should be accessed via their own ref so that I can change individual classNames, depending on what the user is typing (I can do it with a huge state object, but the performance suffers).

If I try to access the classlist of a ref, its undefined. Now I'm not sure if classList is generally not available in functional components or if the refs aren't properly initialized:

const wordsRef = useRef([...Array(1000)].map(() => createRef()));

...

const displayWords = words.map((word, index) => (
    <React.Fragment key={index}>
      <span
        ref={wordsRef.current[index]}
      >
        {word}
      </span>{' '}
    </React.Fragment>
  ));

...

useEffect(() => {
  wordsRef.current[0].classList.add('highlight');
});

...

return (
    <div className={classes.root}>
      {displayWords}
    </div>
  );

Error: Cannot read property 'add' of undefined.

I was only able to find examples with classList, but this is propably not the way to add/remove classes in a functional component?


Solution

  • The code almost works fine, you assigned a reference with .current property, just change it to:

    wordsRef.current[0].current.classList
    

    But you should approach it in other way:

    ref={el => (wordsRef.current = [...wordsRef.current, el])
    
    import React, { useRef, useEffect } from 'react';
    import ReactDOM from 'react-dom';
    
    const words = ['Many', 'Words'];
    
    const App = () => {
      const wordsRef = useRef([]);
    
      const displayWords = words.map((word, i) => (
        <React.Fragment key={i}>
          <span ref={el => (wordsRef.current = [...wordsRef.current, el])}>
            {word}
          </span>
        </React.Fragment>
      ));
    
      useEffect(() => {
        console.log(wordsRef);
        console.log(wordsRef.current[0].classList);
      });
    
      return <div>{displayWords}</div>;
    };
    
    ReactDOM.render(<App />, document.getElementById('root'));
    

    Edit fervent-nobel-0fbof