0

So I am following a tutorial for building a react todo list with a rails api.

When I try to add a task to the list it renders the bullet point but not the text. Checking the console its tells me the error is:

"Warning: Each child in a list should have a unique "key" prop.

But I'm pretty sure I assigned a key prop already?

I checked the line of code in question the {this.state.items.map((item) => (<TodoItem key={item.id} item={item} >{item}</TodoItem> and it appears to be correct So I'm not sure what I'm doing wrong here? This is my TodoList.js


import React, { Component } from "react";
import TodoForm from "./TodoForm";
import TodoItem from "./TodoItem";

const  api_url = "http://localhost:3001/api/v1/todos"

class TodoList extends Component {
    constructor(props) {
      super(props)
      this.state = {
        items: []
      }
      this.updateTodoList = this.updateTodoList.bind(this);

    }

    componentDidMount () {
      this.getTasks();
    }

    getTasks() {
      fetch(api_url)
        .then(response => response.json())
        .then(response_items => {
          this.setState({
            items: response_items.reverse()
          })
      });
    }

    updateTodoList(item) {
      let _items = this.state.items
      // unshift adds to beginning of array
      _items.unshift(item)
      this.setState({
        items: _items
      })
    }

    render() {
        console.log(this.state.items)
        return (
            <div>
                <TodoForm api_url={api_url} updateTodoList={this.updateTodoList} />
                <ul id="todo_list">
                    {this.state.items.map((item) => (
                        <TodoItem key={item.id} item={item} >{item}</TodoItem>
                    ))}
                </ul>
            </div>
        )
    }
}
export default TodoList;

This is my ToDoItem.js

import React from "react";

export default function TodoItem(props) {
    return (
        <li>{props.item.task}</li>
    )
}

Any help on understanding and fixing this error would be appreciated.

  • Does this answer your question? [Understanding unique keys for array children in React.js](https://stackoverflow.com/questions/28329382/understanding-unique-keys-for-array-children-in-react-js) – SuleymanSah Sep 06 '22 at 08:43
  • I'm not sure, my keys all have unique ids as they are generated from a rails api, and rails never duplicates ids. So I really don't understand how I am getting this problem, Checking the api none of my ids are the same. – Laura Brooks Sep 06 '22 at 13:12
  • What do you have in `this.state.items` can you add to the question? Also you need to change this line `{item}` to `` – SuleymanSah Sep 06 '22 at 14:14

3 Answers3

1

Your item.id isn't unique. Try to console.log your item.id to check if they are unique.

Or try:

{this.state.items.map((item, index) => (
    <TodoItem key={index} item={item}>{item}</TodoItem>
))}
Mart
  • 36
  • 2
  • So I tried the above code from @Mart but it is still not rendering when I add a task to the list. I also console logged my ids, and they are all unique. No two are the same. Thanks for the suggestion though. – Laura Brooks Sep 06 '22 at 10:59
0

I fixed the error. I was missing a parenthesis after 'response.json' in my FormSubmit function.

    async formSubmit(formData) {
      var data = new FormData(formData)
      await fetch(this.state.api_url, {
        method: "POST",
        mode: "cors",
        body: data
      }).then(response => response.json)
      .then(response => this.props.updateTodoList(response))
    }

became

    async formSubmit(formData) {
      var data = new FormData(formData)
      await fetch(this.state.api_url, {
        method: "POST",
        mode: "cors",
        body: data
      }).then(response => response.json())
      .then(response => this.props.updateTodoList(response))
    }

and that fixed it.

intotecho
  • 4,925
  • 3
  • 39
  • 54
0

React advises us to not use index as a key, Instead use some sort of unique identifying string.

For Example: You could use package such as 'uuid' which basically just allows you to generate uuid() by installing it as a package.

step1- npm install uuidv4

step2- import {v4 as uuidv4} from 'uuid';

ste3- edit your line of code as below

{this.state.items.map((item) => (<TodoItem key={uuidv4()} item={item} >{item}</TodoItem>

Note : items.map((item, index) => key={index}), This is going to be index of current todo item that's being looped through the items array.

UUID : A Universally Unique Identifier (UUID) is an identifier standard used in many non-MultiValue databases and software to generate a Unique ID outside of using incremental numbers.