DEV Community

Cover image for 🚫😩 An array of react refs
Alex Sharp 🛠sharesecret.co
Alex Sharp 🛠sharesecret.co

Posted on • Updated on • Originally published at ajsharp.com

🚫😩 An array of react refs

Apparently you can't store React refs in an array. For some reason they get wiped out, so if you need to store a collection of refs, you have to do something like this (forgive me lord, for I hath sinned):

import React from 'react'

const collection = ["label 1", "label 2"]

class SinFactory extends React.Component {
  constructor(props) {
    super(props)
    this.ref0 = React.createRef()
    this.ref1 = React.createRef()
  }

  render() {
    return (
      <div>
        {collection.map((label, i) => {
          return <div key={label} 
            ref={this[`ref${i}`]}>{label}
          </div>
        })}
      </div>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

It's truly filthy, but it works.


☝️ Be sure to check out Sharesecret, which makes it easy to securely share sensitive data.

Discussion (8)

Collapse
amantel profile image
Amantel

I tried just now, setting this.myRef = []; and using callbacks ref={(ref) => { this.myRef[someval] = ref; return true; }} - everything worked perfectly.

Collapse
elramus profile image
Luke Ramus

Thanks, this was helpful. If anyone else out there wants to do this with TypeScript and hooks, this worked like a charm for me:

const tentRefs = useRef<(HTMLDivElement | null)[]>([])

<div className="name-tent" key={studentId} ref={(ref) => { tentRefs.current.push(ref) }}>

Collapse
paddy57 profile image
Pradnyanand Milind Pohare

hello, how can i access stored values in myRef, like say what if i want to access next myRef value on currnet myRef, what should i do there? myRef.nextItem ?

Collapse
sunanda3055 profile image
sunanda3055

It worked for me as well. This is really cool. I have never used ref in loop and was facing issues, but with your help it rocked. Thanks!!

Collapse
joostkiens profile image
Joost Kiens • Edited on

How about using a combination of useRef and createRef?

const refs = useRef(collection.map(() => createRef())

return collection.map((x, i) => <div key={i} ref={refs.current[i]}>{x}</div>
Enter fullscreen mode Exit fullscreen mode

The first rule of hooks states we can't call hooks (useRef) in a loop, but we can call createRef in a loop.

The array of refs (from createRef) will not trigger renders and stay in place between renders because it's safely stored in the .current created by useRef.

Using this way, we don't need to know how many refs we need to create upfront and it's a bit less noise (perhaps at the price of a little less clarity). Any downsides with this?

Collapse
iwi4a_24 profile image
Ivelin

I used callback refs by creating an empty array in the parent elementRefs = []; and then while iterating over the child components, I passed a function to the ref attribute ref={el => this.elementRefs[index] = el}. This way, it executes the function in the child, but it has elementRefs in its scope and add itself to the array. So at the end, you end up with an array elementRefs with all the ref elements in it.

Collapse
moaazbhnas profile image
Moaaz Bhnas

There's a solution with hooks: stackoverflow.com/a/56063129/7982963

Collapse
amantel profile image
Amantel

Really? I have a bunch (50+) of buttons to scroll to and I wanted to use refs for those. What a pain.