Reactjs how to use ref inside map function?

25,608

Solution 1

Initialize this.accordionContent as an array

constructor(props) {
    super()
    this.accordionContent =[];
}

And set the ref like this

<div ref={accordionContent => this.accordionContent[key] = accordionContent} className="accordionContent">

Solution 2

Here is my working codepen example based on your code above

Linked example is an "actual" accordion, ie display and hide adjacent content.

(see code snippets below for turning to red)

https://codepen.io/PapaCodio/pen/XwxmvK?editors=0010


CODE SNIPPETS

initialize the referance array:

constructor(props) {
    super();
    this.accordionContent = [];
}

add the ref to the reference array using the key:

<div ref={ref => (this.accordionContent[key] = ref)} >

pass the key to the toggle function via onClick

 <button onClick={() => this.accordionToggle(key)} >

finally reference the key inside the toggle function

accordionToggle = key => {
    this.accordionContent[key].style.color = 'red'
};

Solution 3

I found a way to do it without using ref, by using the key property of the map:

 accordionToggle = (key) => {
        console.log(key)
        var a = document.getElementsByClassName('accordionContent')
        a[key].style.color = 'red'
    }

I'm not sure if it's as good to access the dom like so, instead of using refs to directly target the elements.

Share:
25,608
sir-haver
Author by

sir-haver

Updated on November 27, 2021

Comments

  • sir-haver
    sir-haver over 2 years

    I'm mapping through an array and for each item display a button with text. Say I want that on clicking the button, the text underneath will change its color to red. How can I target the sibling of the button? I tried using ref but since it's a mapped jsx, only the last ref element will be declared.

    Here is my code:

    class Exams extends React.Component {
        constructor(props) {
            super()
            this.accordionContent = null;
        }
        state = {
            examsNames: null, // fetched from a server
        }
        accordionToggle = () => {
            this.accordionContent.style.color = 'red'
        }
        render() {
            return (
                <div className="container">
                    {this.state.examsNames && this.state.examsNames.map((inst, key) => (
                        <React.Fragment key={key}>
                            <button onClick={this.accordionToggle} className="inst-link"></button>
                            <div ref={accordionContent => this.accordionContent = accordionContent} className="accordionContent">
                                <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aperiam, neque.</p>
                            </div>    
                        </React.Fragment>
                    ))}
                </div>
            )
        }
    }
    
    
    export default Exams;
    

    As explained, the outcome is that on each button click, the paragraph attached to the last button will be targeted.

    Thanks in advance

  • sir-haver
    sir-haver over 5 years
    I also found another method which I'm not sure that it's as good but I will post here