Search code examples
reactjsref

how to create refs for content that gets created later


I have a component that fetches data from an api upon user input. This data then gets rendered onto the screen as <li/> tags. I want those <li/> tags to have a ref.

I tried creating an object of refs that I create after the data is fetched:

 this.singleRefs = data.reduce((acc, value) => {
      acc[value.id] = React.createRef();
      return acc;
    }, {});

and then later assign these refs to the <li/> tag: <li ref={this.singleRefs[element.id]}>

but when I print them out I always have {current:null} Here is a demo

what am I doing wrong?


Solution

  • With dynamic ref data, I'd propose that you should use callback refs.

    import React from "react";
    import "./styles.css";
    
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    
    export default class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          data: []
        };
        this.singleRefs = {};
      }
    
      componentDidMount() {
        const data = [
          { value: "val1", id: 1 },
          { value: "val2", id: 2 },
          { value: "val3", id: 3 }
        ];
        this.myFunc(data);
        //you don't need this anymore
        // this.singleRefs = data.reduce((acc, value) => {
        //   acc[value.id] = React.createRef();
        //   return acc;
        // }, {});
      }
    
      myFunc = async (data) => {
        await sleep(3000);
        this.setState({ data });
      };
    
      renderContent() {
        return this.state.data.map(
          function (element, index) {
            return (
              <li key={index} ref={(node) => (this.singleRefs[element.id] = node)}>
                {element.value}
              </li>
            );
          }.bind(this)
        );
      }
    
      render() {
        console.log(this.singleRefs);
        return <ul>{this.renderContent()}</ul>;
      }
    }
    

    Sandbox