1

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

1 Answer 1

1

Your error may be attributable to using same variable name of 'items' in addItems function:

Try changing the name of first argument to 'item' instead.

 const addItems = (item, date) => {
    setItems([...items, {item, date, id: uuidv4()}]);
  };
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.