I use the following hook in a page.tsx file and then pass the data down to a table. When I click on a task, i have the following function
page.tsx
"use client"
const { allOpenTasks, getOpenTasks } = useTasks();
useEffect(() => {
const fetchTasks = async () => {
await getOpenTasks(user.id);
};
fetchTasks();
}, []);
useTasks.tsx
export const useTasks = () => {
const [allOpenTasks, setAllOpenTasks] = useState<any>([]);
const getOpenTasks = async (userId: any) => {
try {
const { data, error } = await supabase
.from("task")
.select(
`
id,
is_complete
`
)
.eq("owner_id", userId);
if (error) {
throw error;
}
if (data) {
setAllOpenTasks(data);
}
} catch (error: any) {
console.log(error.message);
}
};
const setTaskCompleted = function (taskId: any) {
const updatedTasks = allOpenTasks.map((task: any) =>
task.id === taskId ? { ...task, is_complete: !task.is_complete } : task
);
setAllOpenTasks([...updatedTasks]);
};
return {
allOpenTasks,
getOpenTasks,
setTaskCompleted
};
};
Table.tsx
"use client"
const { setTaskCompleted } = useTasks();
const clickCompleteTask = async (taskId: any) => {
try {
const { error } = await supabase
.from("task")
.update({
is_complete: true,
})
.eq("id", taskId);
if (error) throw new Error();
setTaskCompleted(taskId);
} catch (err) {
console.log(err);
}
};
I have tried the following which works.
Instead of keeping the tasks state inside of the hook, i can maintain it in the page.tsx file and only use the hook to fetch the data from supabase.
I think it looks more clean if its inside the hook however it does not re-render on state change for a task object in page.tsx (when its set to completed)
I suspect its because when setTaskCompleted is initialized in the start, the allOpenTasks is empty since supabase hasn’t set that yet.
If there is a better pattern i’d also be open to this.
Thanks!
2
Answers
It was actually how useHooks work. Importing useTasks in two different components led to two separate instances. Instead needed to pass setTaskCompleted down as a prop.
could you try
To address this and ensure a re-render when the data within allOpenTasks changes.
I think it have 2 problems,
if (allOpenTasks.length > 0)
is data is empty if supabase return empty, ensure data is fetched before update i have condition for this.[...allOpenTasks].map
To address this and ensure a re-render when the data withinallOpenTasks
changes.anyway, i think you code is perfect overall