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>
when i clicked trash button it seems like
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