Issue
I'm making a simple to-do app using Next.js + TypeScript + Axios and trying to get the delete button to work.
My delete button deletes the selected task as expected, but I want it to also refresh my tasks list so that I can see the updated list.
Any suggestions would be appreciated. Thanks in advance!
// pages/index.tsx
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import FactCheckIcon from "@mui/icons-material/FactCheck";
import {
List,
ListItem,
ListItemAvatar,
Avatar,
ListItemText,
Container,
Typography,
IconButton,
Stack,
} from "@mui/material";
import { deleteTask } from "../modules/apiClient/tasks/deleteTask";
import { useFetchTasks } from "../modules/hooks/useFetchTasks";
interface OperationButtonProps {
taskId: number;
}
const OperationButtons: React.VFC<OperationButtonProps> = (props) => {
const handleDelete = async () => {
try {
await deleteTask(props.taskId); // calls the API and deletes the task fine
// I have to do something here or somewhere to refresh the tasks list but can't figure out how.
} catch (e) {
console.log(e);
}
};
return (
<Stack direction="row">
<IconButton aria-label="edit">
<EditIcon />
</IconButton>
<IconButton edge="end" aria-label="delete" onClick={handleDelete}>
<DeleteIcon />
</IconButton>
</Stack>
);
};
const IndexPage = () => {
const { tasks } = useFetchTasks();
return (
<>
<Typography variant="h3" align="center" marginTop={3}>
TODO LIST
</Typography>
{tasks && (
<Container maxWidth="sm">
<List sx={{ width: "100%" }}>
{tasks.tasks.map((task) => (
<ListItem
key={task.id}
secondaryAction={<OperationButtons taskId={task.id} />}
>
<ListItemAvatar>
<Avatar>
<FactCheckIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={task.description}
secondary={task.created_at}
/>
</ListItem>
))}
</List>
</Container>
)}
</>
);
};
export default IndexPage;
// modules/hooks/useFetchTasks.ts
import { useState, useEffect, useCallback } from "react";
import { getTasks, TasksResponse } from "../apiClient/tasks/getTasks";
export const useFetchTasks = () => {
const [tasks, setTasks] = useState<TasksResponse | null>(null);
const fetchTasks = useCallback(async () => {
try {
const { data } = await getTasks();
setTasks(data);
} catch (e) {
console.log(e);
}
}, []);
useEffect(() => {
fetchTasks();
}, []);
return {
tasks,
fetchTasks,
};
};
Solution
You can return setTasks
your useFetchTasks
and pass it to your button, so you can update your list after called API
const OperationButtons: React.VFC<OperationButtonProps> = (props) => {
const handleDelete = async () => {
try {
await deleteTask(props.taskId);
props.setTasks(prevTasks => prevTasks.tasks.filter(task => task.id !== props.taskId))
} catch (e) {
console.log(e);
}
};
return (
<Stack direction="row">
<IconButton aria-label="edit">
<EditIcon />
</IconButton>
<IconButton edge="end" aria-label="delete" onClick={handleDelete}>
<DeleteIcon />
</IconButton>
</Stack>
);
};
const IndexPage = () => {
const { tasks, setTasks } = useFetchTasks();
return (
<>
<Typography variant="h3" align="center" marginTop={3}>
TODO LIST
</Typography>
{tasks && (
<Container maxWidth="sm">
<List sx={{ width: '100%' }}>
{tasks.tasks.map((task) => (
<ListItem
key={task.id}
secondaryAction={<OperationButtons taskId={task.id} setTasks={setTasks} />}
>
<ListItemAvatar>
<Avatar>
<FactCheckIcon />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={task.description}
secondary={task.created_at}
/>
</ListItem>
))}
</List>
</Container>
)}
</>
);
};
export const useFetchTasks = () => {
const [tasks, setTasks] = (useState < TasksResponse) | (null > null);
const fetchTasks = useCallback(async () => {
try {
const { data } = await getTasks();
setTasks(data);
} catch (e) {
console.log(e);
}
}, []);
useEffect(() => {
fetchTasks();
}, []);
return {
tasks,
fetchTasks,
setTasks
};
};
export default IndexPage;
Answered By - iamhuynq Answer Checked By - Robin (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.