I'm following a tutorial to make a React todo app. I have components and contexts files. I have addItem function but when I clicked 'Add todo' button, the item and date is not rendering into todo list. Also, it shows an error as Warning: Each child in a list should have a unique "key" prop. even though I have given an id.
Since I am following the tutorial, I don't know where I did wrong. Would be appreciated if anyone could tell what is wrong.
App.js
import React from 'react';
import Navbar from './components/Navbar';
import Form from './components/Form';
import TodoList from './components/TodoList';
import TodoContextProvider from './contexts/TodoContexts';
function App() {
return (
<div className="App">
<TodoContextProvider>
<Navbar />
<TodoList />
<Form />
</TodoContextProvider>
</div>
);
}
export default App;
TodoContexts.js
import React, { createContext, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
export const TodoContext = createContext();
const TodoContextProvider = (props) => {
const [items, setItems] = useState([
{items: 'laundry', date: '2020-11-18', id: 1},
{items: 'lunch', date: '2020-11-20', id: 2}
]);
const addItems = (items, date) => {
setItems([...items, {items, date, id: uuidv4()}]);
};
const removeItems = (id) => {
setItems(items.filter(item => item.id !== id));
};
return (
<TodoContext.Provider value={{ items, addItems, removeItems }}>
{props.children}
</TodoContext.Provider>
)
}
export default TodoContextProvider
TodoList.js
import React, { useContext } from 'react';
import TodoDetails from './TodoDetails';
import { TodoContext } from '../contexts/TodoContexts';
const TodoList = () => {
const { items } = useContext(TodoContext);
return items.length ? (
<div className="todo-list">
<ul>
{items.map(item => {
return ( <TodoDetails item={item} key={item.id} /> )
})}
</ul>
</div>
) : (
<div className="empty">You have no todos at the moment.</div>
)
}
export default TodoList
TodoDetails.js
import React, { useContext } from 'react';
import { TodoContext } from '../contexts/TodoContexts';
const TodoDetails = ({ item }) => { //TodoList item is props
const { removeItems } = useContext(TodoContext);
return (
<li onClick={() => removeItems(item.id)}>
<div className="items">{item.items}</div>
<div className="date">{item.date}</div>
</li>
)
}
export default TodoDetails
Form.js
import React, { useState, useContext } from 'react';
import './Form.css';
import { TodoContext } from '../contexts/TodoContexts';
const Form = () => {
const {addItems} = useContext(TodoContext);
const [items, setItems] = useState('');
const [date, setDate] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(items, date);
addItems(items, date);
setItems('');
setDate('');
}
return (
<form className="form" onSubmit={handleSubmit}>
<input
type="text"
value={items}
placeholder="Enter todo"
onChange={(e) => setItems(e.target.value)}
/>
<input
type="date"
value={date}
onChange={(e) => setDate(e.target.value)}
/>
<input type="submit" value="Add todo"/>
</form>
)
}
export default Form
Navbar.js
import React, { useContext } from 'react';
import { TodoContext } from '../contexts/TodoContexts';
const Navbar = () => {
const { items } = useContext(TodoContext);
return (
<div>
<h1>Todo List</h1>
<p>Currently you have {items.length} todos to get through...</p>
</div>
)
}
export default Navbar