Home > Mobile >  change state of clicked target inside mapped array
change state of clicked target inside mapped array

Time:12-22

I'm trying to change the state inside a map array. my state is shared in all the items created by the map array and I'm trying to change the state of the clicked item, here's the code:

{dbData ?
            dbData.map((item, i) => (
                <Box id={item.id} className={`${cl.FolderStyles} ${activeFolderStyles}`} key={i} onClick={activeFolder}>
                    <FolderIcon className={cl.folder_icon} />
                    {item.name}
                </Box>
            ))
            : <img src={loader} alt="loader" />
        }

here you can see im creating multiple items, and the state is: "activeFolderStyles", what i want is to add a class to the clicked item which becomes active but my problem is that the state of all the items is changed after clicking and all become active.

            const [activeFolderStyles, setActiveFolderStyles] = useState();
          const activeFolder = (e) => {
            const id = e.target.id;
            const element = document.getElementById(id);
            console.log(element);
            if (element.classList.contains(side_cl.folderActive)) {
              setActiveFolderStyles("");
            }
            else {
              setActiveFolderStyles(side_cl.folderActive);
            }
          }

here is the state that im using.

 const [activeFolderStyles, setActiveFolderStyles] = useState();
  const activeFolder = (e) => {
    const id = e.target.id;
    const element = document.getElementById(id);
    if (element.classList.contains(side_cl.folderActive)) {
      setActiveFolderStyles("");
    }
    else {
      setActiveFolderStyles(side_cl.folderActive);
    }

}

So i dont really know how to point out the targeted state and not all

CodePudding user response:

You can maintain some state that defines what the currently active folder is. The state will identify the currently active folder using its id, which can be obtained when you map dbData. While mapping, you can check if the current item.id of the current item is equal the active id in your state, and if it is, add your class, otherwise, don't add the class at all (note, activeFolder in the below JSX refers to the new state value we're creating to keep track of the active folder id, not your click event handler function from your question):

{dbData ?
  dbData.map((item, i) => (
    <Box id={item.id} className={`${cl.FolderStyles} ${item.id === activeFolder ? side_cl.folderActive : ""}`} key={item.id} onClick={() => handleFolderClick(item.id)}>
      <FolderIcon className={cl.folder_icon} />
      {item.name}
    </Box>
   ))
   : <img src={loader} alt="loader" />
}

Then you can create your activeFolder state:

const [activeFolder, setActiveFolder] = useState();

You can then update this state when you click your folder to the current folder:

// Use this instead of your `activeFolder` function
const handleFolderClick = (newItemId) => {
  // If the folder we're activating is already "active", deactivate it, otherwise, update the state to point to activate our new folder
  setActiveFolder(currItemId => currItemId === newItemId ? "" : newItemId);
}

The above JSX uses the above handleFolderClick function by passing through the item id of the box that was clicked.

Side note: DOM methods like getElementById(), querySelectorAll() etc. are rarely ever used in React, if you find yourself using them then there is a good chance that you're not doing something in the way it was intended, where a component's state should be used to help drive the component logic and what it renders.

CodePudding user response:

You can do this in a much cleaner way like so

<Box id={item.id} className={item.id === activeFolderStyles ? "ACTIVE CLASSNAME" : "NOT ACTIVE CLASSNAME"} key=. 
   {i} onClick={setActiveFolderStyles(item.id)}>
   <FolderIcon className={cl.folder_icon} />
   {item.name}
</Box>
  • Related