Home > Back-end >  to unique useState variable for repeated item in ReactJS
to unique useState variable for repeated item in ReactJS

Time:06-05

I am newbie in reactjs. How can set a variable for every single iterating items? I have some list and when click trash icon i want to show loading icon just for clicked item

const [deleteLoading, setDeleteLoading] = useState(false);

<ul className="mt-2">
   {projects && projects.map((project, index) =>  (
    <li key={index}>
     <NavLink to={`someurl`}>{project.project_name}</NavLink>
              
     <span className={`${deleteLoading ? "" : "hidden"}`}>
      <svg> ..loading icon.. </svg>
     </span>

     <span onClick={() => deleteProject(project._id)} className={`${deleteLoading ? "hidden" : ""}`}>
       <svg> ..trash icon.. </svg>
     </span>
    </li>)
   )}
</ul>

my list

when i clicked trash button it seems like

enter image description here

const deleteProject = async (id) => {
  setDeleteLoading(true)

  // some deleting code..
}

CodePudding user response:

The behaviour you have is normal here because you use the same logic for every elements in your map function : ${deleteLoading ? "" : "hidden"}

If you want to have the delete icon only in the good project you should instead define a state var like deletingProject which contain the ID or the name of the deleting project.

Then you just have to modify the loading icon span like this :

<span className={`${project.project_id === deletingProject ? "" : "hidden"}`}>

CodePudding user response:

I would suggest creating a component to hold each project, and add the delete functionality to the individual component. For example:

Project.js

export default function Project({ project, index }) {
  const [deleteLoading, setDeleteLoading] = useState(false);
  return (
    <li key={index}>
     <NavLink to={`someurl`}>{project.project_name}</NavLink>
              
     <span className={`${deleteLoading ? "" : "hidden"}`}>
      <svg> ..loading icon.. </svg>
     </span>

     <span onClick={() => deleteProject(project._id)} className={`${deleteLoading ? "hidden" : ""}`}>
       <svg> ..trash icon.. </svg>
     </span>
    </li>
}
}

And then import into the Parent component

import Project from './Project.js'
export default function Parent(props) {
  return (
  <ul className="mt-2">
   {projects && projects.map((project, index) =>  (
     <Project project={project} index={index}/>
   )}
  </ul>
)
)}

I hope that helps

CodePudding user response:

If you want to keep each project logic and state separate I'd suggest to create another component and host any project related logic there.

An example

function ProjectItem({ name }) {
  const [deleteLoading, setDeleteLoading] = useState(false)

  function handleDelete() {
    // Some logic here
    setDeleteLoading(true)
  }
  return (
    <li>
      <NavLink to={`someurl`}>{name}</NavLink>
      <span className={`${deleteLoading ? "" : "hidden"}`}>
        <svg> ..loading icon.. </svg>
      </span>

      <span
        onClick={handleDelete}
        className={`${deleteLoading ? "hidden" : ""}`}
      >
        <svg> ..trash icon.. </svg>
      </span>
    </li>
  )
}

function MainComponent() {
  return (
    <ul className="mt-2">
      {projects &&
        projects.map((project) => (
          <ProjectItem key={project._id} name={project.project_name} />
        ))}
    </ul>
  )
}

NOTES: Never use index as key prop in React Components. If you have an id already then use that as it's key value. Key prop is intended to be unique among all your rendered components

If you have items that can have it's own state move them to a new component. Hope you end up liking React and learning a lot my man ;3

  • Related