I’m making my first react app, a to-do list. Everything seems quite fine, the only problem I have is that the delete and complete buttons only work after refreshing a page. Well, actually they work pretty well and as they should (I mean, I can see the console.log results in the console after clicking a button), but the front-end results I can only see after refreshing my app. I really don’t know what’s going on. Here’s the code (it’s pretty long, but I don’t know where the issue lies, so I’m showing all of it):
import React from "react";
import "./App.css";
import axios from "axios";
import { Trash, Check } from "@phosphor-icons/react";
import { useState, useEffect } from "react";
axios.defaults.baseURL = "http://localhost:3000";
function App() {
const [activeTab, setActiveTab] = useState('ToDoTab');
const [inputName, setInputName] = useState("");
const [inputDescription, setInputDescription] = useState("");
const [tasks, setTasks] = useState([]);
const [completedTasks, setCompletedTasks] = useState([]);
useEffect(() => {
const resp = axios.get("/todos").then((resp) => {
setTasks(resp.data);
});
}, []);
useEffect(() => {
const completedResp = axios.get("/completedTodos").then((completedResp) => {
setCompletedTasks(completedResp.data);
});
}, []);
const handleTabClick = (tabId) => {
setActiveTab(tabId);
};
async function addTask(e) {
const data = {
name: inputName,
desc: inputDescription,
status: "false",
}
const resp = await axios.post("/todos", data);
if (resp.data.success) {
setTasks((prevTasks) => [...prevTasks, resp.data.newTask.rows[0]]);
}
setInputName("");
setInputDescription("");
};
async function completeTask(e, todo) {
const resp = await axios.put(`/todos/${todo.taskID}`);
if (resp.data.success) {
setTasks(prevTasks => prevTasks.filter(t => t.taskID !== todo.taskID));
}
};
async function deleteTask(e, todo) {
const resp = await axios.delete(`/todos/${todo.taskID}`);
if (resp.data.success) {
setTasks(prevTasks => prevTasks.filter(t => t.taskID !== todo.taskID));
}
};
return (
<div className="background">
<header className="todos-header">
<p className="header-text">My Todos</p>
<div className="box">
{/* Form */}
<form onSubmit={e => e.preventDefault()}>
<table className="table-one">
<tbody>
<tr>
<th><label htmlFor="title">Title:</label></th>
<th><label htmlFor="info">Description:</label></th>
</tr>
<tr>
<td><input
type="text"
id="title"
name="title"
placeholder={inputName ? "" : "What's the title of your To Do?"}
value={inputName}
onChange={(e) => setInputName(e.target.value)}></input></td>
<td><input
type="text"
id="info"
name="info"
placeholder={inputDescription ? "" : "What's the title of your To Do?"}
value={inputDescription}
onChange={(e) => setInputDescription(e.target.value)}></input></td>
<td><button
type="button"
className="add-button"
onClick={addTask}>Add</button></td>
</tr>
</tbody>
</table>
</form>
<div className="tasks">
<button
onClick={() => handleTabClick('ToDoTab')}
style={{ backgroundColor: activeTab === 'ToDoTab' ? '#02e77e' : '#5c5c5c' }}>To Do</button>
<button
onClick={() => handleTabClick('CompletedTab')}
style={{ backgroundColor: activeTab === 'CompletedTab' ? '#02e77e' : '#5c5c5c' }}>Completed</button>
{/* To Do boxes */}
<div className="tasks-holder" id="ToDoTab" style={{ display: activeTab === 'ToDoTab' ? 'block' : 'none' }}>
{tasks.map((todo, index) => {
return (
<div className="tasks-box" key={todo.taskID}>
<table className="table-two">
<tbody>
<tr>
<td>
<h1>{todo.name}</h1>
<p>{todo.description}</p>
</td>
<td>
<Trash className="icon-space trash" size={40} color="#fff" onClick={(e) => deleteTask(e, todo)} />
<Check className="icon-space check" size={40} color="#02e77e" onClick={(e) => completeTask(e, todo)} />
</td>
</tr>
</tbody>
</table>
</div>
);
})}
</div>
{/* Completed boxes */}
<div className="tasks-holder" id="CompletedTab" style={{ display: activeTab === 'CompletedTab' ? 'block' : 'none' }}>
{completedTasks.map((todo, index) => {
return (
<div className="tasks-box" key={todo.taskID}>
<table className="table-two">
<tbody>
<tr>
<td>
<h1>{todo.name}</h1>
<p>{todo.description}</p>
</td>
<td>
<Trash className="icon-space trash" size={40} color="#fff" style={{marginLeft: '20px'}} onClick={(e) => deleteTask(e, todo)} />
</td>
</tr>
</tbody>
</table>
</div>
);
})}
</div>
</div>
</div>
</header>
</div>
);
}
export default App;
Everything on the back-end seems fine. I’ve already checked if there are any issues on the server, but it’s not delaying anything, I think it works just as it should. I’ve also tried triggering the rerendering but it doesn’t work as well and there are no errors in the console.