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:-
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.