I've created Context.Provider
component which has in it's context state and action function:
//AppProvider.tsx//
import { createContext, useContext, useState } from "react";
export const AppContext = createContext<IAppContext>({
state: {
taskList: []
},
actions: {
addTask: (_title: ITask["title"]) => { }
},
});
export const AppProvider = ({ children }: { children: React.ReactNode }) => {
const [taskList, setTaskList] = useState<IAppContext['state']['taskList']>([]);
const addTask = (title: ITask["title"]) => {
let id = `task_${Math.round(Math.random() * 1000000)}`;
setTaskList([...taskList, { id, title, steps: [] }]);
};
};
const value = {
state: {
taskList: taskList
},
actions: {
addTask
},
};
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
};
export const useData = () => {
return useContext(AppContext)
}
In my NewTask
component I've got access to the context and call addTask
function:
NewTask.tsx
import { useRef } from "react";
import { useData } from "../../../AppProvider";
export default function NewTask() {
const inputRef = useRef<Nullable<HTMLInputElement>>(null);
const { actions: { addTask } } = useData();
const handleAddTask = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (inputRef.current) {
let inputText = inputRef.current.value
if (inputText.length > 0) {
addTask(inputText)
inputRef.current.value = ""
}
}
}
return <div className={styles.newTask}>
<form className={styles.form} onSubmit={handleAddTask}>
<input type="text" placeholder="Add new task..."
name="title" className={styles.newTask} ref={inputRef} />
<button className={styles.iconButton} >
<img src="icons/plus.png" alt="Add task" />
</button>
</form>
</div>;
}
As an output for taskList
I've all ids replaced with the last id value:
How to fix this bug?
I've tried to change addTask
function to this one, but with no luck:
const addTask = (title: ITask["title"]) => {
let id = `task_${Math.round(Math.random() * 1000000)}`;
setTaskList((tasks) =>
tasks.concat([{ id, title, steps: [] }])
);
};
Reprodused example on codesandbox
Your problem is in your Task
component. Your .filter()
condition is written incorrectly:
const [task] = state.taskList.filter((task) => task.id = id);
Here task.id = id
is not performing a comparison, it's assigning task.id
to id
, hence why all your task objets within your state end up with the same id. You could change this to use ==
or ===
, but you don't need to do an additional search on your array here. Instead, pass the task
from your TaskList
component into Task
:
return (
<ol className="taskList">
{taskList.map((task) => (
<Task key={task.id} task={task} />
))}
</ol>
);
Then your Task
component can use task
directly, no more filtering required (note the fragement <></>
isn't required here, but perhaps your actual code has multiple JSX elements you want to return):
export default function Task({ task }: {task: ITask}) {
return (
<>
<p className="title">{`Task_Title- ${task.title}`}</p>;
</>
);
}