How to re-render divs using ref keeping the declaration order?

Viewed 63

Lets say I have ref variable that contains a list of divs:

const refDivs = useRef()

This ref has the format { current = [divC1,divC2,divC3,divC1,divC2,divC4]} and is filled using :

<c>
 <c1 parentRef={refDivs}/>
 <c2 parentRef={refDivs}/>
 <c3 parentRef={refDivs}/>
<c/>
<c>
 <c1 parentRef={refDivs}/>
 <c2 parentRef={refDivs}/>
 <c4 parentRef={refDivs} />
<c/>

I need to re-render the ref variable content in somewhere else -after doing some extra calculations- but the order is altered (e.g. { current = [divC4,divC2,divC3,divC1,divC1,divC2]} - sometimes its different) . I believe this is because rendering is async (right?). So, what would be the best way to ensure the order of this new renders keep the same order as the original one?

<div>{refDivs.current.map(d=>d)}</div>

I tried using like an index prop in the ref object , and order the items before re-rendering again, but its difficult to keep track of the hundreds of components I have (c4,c5, ... c100)

So basically what I want to see is the following :

 <c1 />
 <c2 />
 <c3 />
 <c1 />
 <c2 />
 <c4 />
1 Answers

Here is the example for you - everything is ok:

const C1 = (props) => {
    const ref = React.useRef(null);
    React.useEffect(() => {
      if (!props.parentRef.current) props.parentRef.current = [];
      if (props.parentRef.current.indexOf(ref.current)) {
          props.parentRef.current.push(ref.current);
      }
    }, []);

    return <div ref={ref}>C1</div>
}
const C2 = (props) => {
    const ref = React.useRef(null);
    React.useEffect(() => {
      if (!props.parentRef.current) props.parentRef.current = [];
      if (props.parentRef.current.indexOf(ref.current)) {
          props.parentRef.current.push(ref.current);
      }
    }, []);

    return <div ref={ref}>C2</div>
}
const C3 = (props) => {
    const ref = React.useRef(null);
    React.useEffect(() => {
      if (!props.parentRef.current) props.parentRef.current = [];
      if (props.parentRef.current.indexOf(ref.current)) {
          props.parentRef.current.push(ref.current);
      }
    }, []);

    return <div ref={ref}>C3</div>
}
const C4 = (props) => {
    const ref = React.useRef(null);
    React.useEffect(() => {
      if (!props.parentRef.current) props.parentRef.current = [];
      if (props.parentRef.current.indexOf(ref.current)) {
          props.parentRef.current.push(ref.current);
      }
    }, []);

    return <div ref={ref}>C4</div>
}

const C = (props) => {
  return <div>{props.children}</div>
}

const App = () => {
  const refDivs = React.useRef();
  const [divs, setDivs] = React.useState([]);

  React.useEffect(() => {
    setDivs(refDivs.current);
  }, [])
  return(
    <div className="box">
      <h1>Original divs</h1>  
        <C>
          <C1 parentRef={refDivs}/>
          <C2 parentRef={refDivs}/>
          <C3 parentRef={refDivs}/>
        </C>
        <C>
          <C1 parentRef={refDivs}/>
          <C2 parentRef={refDivs}/>
          <C4 parentRef={refDivs}/>
        </C>
      <div>
        <h1>Referred divs</h1>
        <div 
          dangerouslySetInnerHTML={{
            __html: divs.reduce((html, div) => {
              return html + div.outerHTML}, '')
            }
        }/>
      </div>
    </div>
  );
}


ReactDOM.render(<App />,
document.getElementById("root"))
body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
}
.box {
  width: 300px;
  h1 {
    font-size: 20px;
    margin: 0 0 1rem 0;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related