Im making a project where you can have multiple todo lists which is managed by one big state.
Whenever you add a new item into the todo list the state gets updated twice the first time with the same value and then only once when you add another task. Also the new tasks don’t render. I want them to render and be put inside of the Task component.
import NewProj from "./components/NewProj";
import Button from "./components/Button";
import NoProj from "./components/NoProj";
import TodoList from "./components/TodoList";
import ColumnButton from "./components/ColumnButton";
import {useState, useRef } from "react";
function App() {
const [masterTable, setMasterTable] = useState([]);
const [pageIndex, setPageIndex] = useState({
index: undefined,
page: false,
proj: false,
});
function handleNewProj(title, desc, dueDate) {
setMasterTable((prev) => {
const id = Math.random();
console.log(...prev);
return [...prev, {
id: id,
title: title,
desc: desc,
dueDate: dueDate,
tasks: []
}];
});
}
function handlePage() {
setPageIndex((prev) => {
return {
...prev,
page: true,
proj: false,
}
});
}
function handleIndex(id) {
const theIndex = masterTable.findIndex((proj) => proj.id === id);
// console.log("theIndex: " + theIndex);
setPageIndex(() => {
return {
index: theIndex,
proj: true,
page: false,
}
});
}
// This adds the new task into the masterTable state
function handleAddTask(task, index) {
setMasterTable((prev) => {
let prevRows = prev[index].tasks;
const newRows = [...prevRows, task];
let prevTable = prev;
prevTable[index].tasks = newRows;
return prevTable;
});
}
return (
<>
<div className="flex flex-row w-screen mt-16">
<div className="flex flex-col flex-wrap pl-12 bg-black w-[35%] s-12 h-screen rounded-tr-3xl rounded-br-3xl min-w-[300px] max-w-[400px]">
<p className="text-white text-2xl font-semibold mt-[70px]">YOUR PROJECTS</p>
<Button title="+ Add Project" newPage={handlePage} />
<div className="flex flex-col ">
{masterTable.map((obj, index) => <ColumnButton key={index} id={obj.id} title={obj.title} onC={handleIndex}/>)}
</div>
</div>
{ (!pageIndex.page && !pageIndex.proj) && <NoProj newPage={handlePage} />}
{pageIndex.page && <NewProj handleSubmit2={handleNewProj} /> }
{pageIndex.proj && <TodoList {...masterTable[pageIndex.index]} index={pageIndex.index} addTask={handleAddTask}/> }
</div>
</>
);
}
export default App;
And this the TodoList component where you add a task into the masterTable state
import Task from "./Task"
import { useRef, useState } from "react"
export default function TodoList({id, title, desc, dueDate, tasks, addTask, index}) {
const taskInput = useRef();
return <div className="flex flex-col mt-20 ml-10 w-[40%] ">
<div className="flex flex-row justify-between mb-4">
<p className=" text-3xl font-bold">{title}</p>
<button className="w-[80px] h-10 hover:text-red-600">Cancel</button>
</div>
<p className="mb-4 text-stone-400">{dueDate}</p>
<p className="mb-4 leading-loose border-b-2 pb-4 border-stone-300">{desc}</p>
<p className="mt-1 text-3xl font-bold">Tasks</p>
<div className="flex flex-row items-center">
<input ref={taskInput} className="mt-5 bg-stone-200 rounded-[3px] h-9 p-2 caret-stone-500 min-w-[250px] focus:ring-2 focus:ring-blue-500 focus:outline-none"></input>
<button onClick={() => {
const task = taskInput.current.value;
addTask(task, index);
}} className="rounded-lg p-2 ml-2 text-stone-600 h-9 mt-5 w-fit">Add Task</button>
</div>
<div className="mt-7 bg-stone-200 p-7 divide-y-[20px] divide-stone-200 rounded-sm ">
{tasks.map((task) => {
<Task text={task} />
})}
</div>
</div>
}
I tried instead of getting the value from the input element with ref and instead with useState which did display the tasks but only when you typed a letter into the input box which is not what i want. Also it still had added the same task twice when putting in the first task.