0

I was playing with React Hooks and I tried to create an accordion. I am trying to itreate it from an array. So I have 2data, When I consoled the index, I'm getting the exact index of the clicked button. But when I consoled the ref , I'm getting the ref of the second one but not the first one.

How is this happening? Is it a bug in react?

Here is the sample code

 const content = useRef(null);


    const accordionClick = (id) => {
        setHeightState(setActive === false ? "0px" : `${content.current.scrollHeight}px`);
        SetCustomIndex(id);
        console.log(id);
        console.log(content );
    };

 items.general.map((data, index) => (
      <div className={`accordion-container`} key={index}>
         <button className{`accordion ${setActive}`} onClick{()=>accordionClick(index)}>
            {data}
          </button>

           <div
              className={`panel`}
              ref={content}
              data-id={index}
              style={{
                height: `${setHeight}`,
             }}
               data-id={index}
            >
             <p className="description-14">{data.item.main}</p>
            </div>
7
  • 1
    That's because you use the same ref for several DOM nodes rendered by the cycle. Why do you need to show/hide elements by setting the panels' height? Is there a strict requirement? What if I can offer another way to do so? Commented Apr 7, 2020 at 17:40
  • So that I can get the slide in and out animation , If you have a better approach then please I would love to check that out Commented Apr 7, 2020 at 17:43
  • I got it fixed. I should have figured out about giving index to the ref aswell. Thanks for your time too man <3 Commented Apr 7, 2020 at 17:48
  • Uhh. Height animation to "auto"... I would create some wrapper for the panel that would handle the visibility and height animation and just pass the visibility flag to it based on the currently selected id in the state. The way you're trying do solve your task now is not the declarative React way. Commented Apr 7, 2020 at 17:51
  • @OleksandrKovpashko ohh, I got your pont , I'll try that then. Thank you :) Commented Apr 7, 2020 at 17:53

1 Answer 1

4

Since you are using map(), use ref with Array

const inputRef = useRef([]);

ref={el => inputRef.current[index] = el}

Usage

inputRef.current[index];

Minimum reproducible sample:

const App = () => {
const list = [...Array(4).keys()];
const inputRef = React.useRef([]);
const handler = idx => e => {
  const next = inputRef.current[idx + 1];
  if (next) {
    next.focus()
  }
};
return (
  <div className="App">
    <div className="input_boxes">
      {list.map(x => (
        <input
          key={x}
          ref={el => inputRef.current[x] = el}
          onChange={handler(x)}
        />
      ))}
    </div>
  </div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

ohhhhh,Man thank you. I should have guessed this . Been working for 12hours straight , My brain must be exhausted, THANK YOU SO MUCH THOUGH

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.