Home > other >  Replace specific value in useRef() array in loop
Replace specific value in useRef() array in loop

Time:09-08

I have created multiple dropdowns and I am trying to replace the TITLE dynamically when user clicks on an dropdown option. So when user clicks on a dropdown option, the title on the top of the dropdown changes. I used useRefs on each dropdown loop through a .map() array function.

I managed to change the title values on the array and I have tried to dynamically replace a value in a looped useRef array but i cant figure out to get it working. I tried to replace it using setState hook but its giving me an error and the .map() is not working.

Any tips will be greatly appreciated! heres my what the dropdowns look like:-

Link to codepen:-

enter image description here

enter image description here

JSX: -

  const [isSortButtonClicked, setIsSortButtonClicked] = useState(false);
  const [buttonTitles] = useState(defaultTitles);
  const [chosenTitles, setChosenTitles] = useState([]);
  const [isDropdownOpen, setIsDropdownopen] = useState(false);
  let buttonRef = useRef([]);

  // set chosen titles ----------------------------------
  const handleSort = () => {
    setChosenTitles((chosenTitles) => [
      ...chosenTitles,
      buttonTitles[0],
      buttonTitles[1],
      buttonTitles[2]
    ]);
    setIsSortButtonClicked(true);
  };

  /* trying fix implementation for change title */
  // handle change title --------------------------------
  const handleChangeTitle = (index, indexOfDiv) => {
    console.log("index of buttonTitles", index);
    console.log("index of chosenTitle", indexOfDiv);
    console.log(buttonTitles[index]);

    // this is what i have so far, but it does not work
    // setChosenTitles(
    //   (chosenTitles[index] = buttonTitles[indexOfDiv])
    // );
  };

  // close dropdown -------------------------------------
  useEffect(() => {
    if (!isDropdownOpen) {
      chosenTitles.forEach((_, index) => {
        buttonRef.current[index].classList.remove("active");
      });
    }
  }, [chosenTitles, isDropdownOpen]);

  // open dropdown
  const handleOpenDropdown = (indexOfDiv) => {
    setIsDropdownopen((prev) => !prev);
    buttonRef.current[indexOfDiv].classList.add("active");
  };

  // handle hover background change ----------------------
  const [indexOfTitle, setIndexOfTitle] = useState();
  const handleHoverTitle = (indexOfDiv) => {
    setIndexOfTitle(indexOfDiv);
  };

Return statement:-

return (
    <>
      {isSortButtonClicked ? (
        ""
      ) : (
        <button onClick={handleSort} className="sortBtn">
          Sort
        </button>
      )}

      {chosenTitles.map((title, indexOfDiv) => {
        return (
          <div
            key={indexOfDiv}
            className="dropdown"
            ref={(ref) => (buttonRef.current[indexOfDiv] = ref)}
          >
            <div
              className="button"
              onClick={() => handleOpenDropdown(indexOfDiv)}
            >
              {title}
              {CHEVRON_DOWN}
            </div>

            <div className="content">
              {buttonTitles.map((buttonTitle, index) => {
                return (
                  <div
                    key={index}
                    onClick={() => handleChangeTitle(index, indexOfDiv)}
                    onm ouseEnter={() => handleHoverTitle(index)}
                    style={{
                      background:
                        index === indexOfTitle && "rgba(55, 53, 47, 0.08)"
                    }}
                  >
                    <p>{buttonTitle}</p>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </>
  );

CodePudding user response:

If im understanding your post right. I would recommend replacing your "handleChangeTitle" function to something like this:

const handleChangeTitle = (index, indexOfDiv) => {
    setChosenTitles(
      chosenTitles.map((e, i) => {
        return i == indexOfDiv ? buttonTitles[index] : e;
      })
    );
  };

I also edited it right into your codesandbox: https://codesandbox.io/s/serene-panini-nmxfgv

Altough it would not fix the wrong style of your application. You need to divide your dropdown in components. Thats what React is made for. Then you will also have a clean and structured way to store the dropdowns data.

  • Related