Home > Blockchain >  React - Encountered two children with the same key
React - Encountered two children with the same key

Time:11-09

I'm fairly new to React. I am working on a note app and when I add 2 notes, they have the same key and the next 2 notes also share their own key and so on. I started off with prop drilling from the App to the AddNote file via NotesList.js and it was working fine and the problem has only occurred since I used useContext API so maybe I am not coding the useContext in the correct way. The useContext component looks like this:

import { createContext } from "react";

const HandleAddContext = createContext();
export default HandleAddContext;

This is my App.js

import { useState } from "react";

import { v4 as uuid } from "uuid";

import NotesList from "./components/NotesList";
import HandleAddContext from "./components/UseContext/HandleAddContext";

const unique_id = uuid();
const small_id = unique_id.slice(0, 8);

const initialState = [
  {
    id: small_id,
    text: "1st note",
    date: "12/10/22022",
  },
  {
    id: small_id,
    text: "2nd note",
    date: "15/10/22022",
  },
  {
    id: small_id,
    text: "3rd note",
    date: "16/10/22022",
  },
  {
    id: small_id,
    text: "4th note",
    date: "30/10/22022",
  },
];

export const App = () => {
  const [notes, setNote] = useState(initialState);

  const addHandleNote = (text) => {
    console.log(text);
    const date = new Date();
    const newNote = {
      id: small_id,
      text: text,
      date: date.toLocaleDateString(),
    };

    console.log(newNote);
    const newNotes = [...notes, newNote];
    setNote(newNotes);
  };

  return (
    <HandleAddContext.Provider value={addHandleNote}>
      <div className="container">
        <NotesList notes={notes} />
      </div>
    </HandleAddContext.Provider>
  );
};

export default App;

This is the component with map notes

import Note from "./Note";
import AddNote from "./AddNote";

const NotesList = ({ notes }) => {
  return (
    <div className="notes-list">
      {notes.map((note) => (
        <Note key={note.id}  id={note.id} text={note.text} date={note.date} />
      ))}
      <AddNote />
    </div>
  );
};

export default NotesList;

This is the Note:

import { RiDeleteBin6Line } from "react-icons/ri";

const Note = ({ text, date }) => {
  return (
    <div className="note">
      {/* <div> */}
      <p>{text}</p>
      {/* </div> */}
      <div className="note-footer">
        <p className="note-footer-text">{date}</p>
        <RiDeleteBin6Line />
      </div>
    </div>
  );
};

export default Note;

This is the AddNote.js component

import { useState } from "react";
import { RiSave2Line } from "react-icons/ri";

const AddNote = ({ handleAddNote }) => {
  const [addText, setAddText] = useState("");
  const [errorMsg, setErrorMsg] = useState("");

  //handle text input
  const handleChange = (e) => {
    console.log(e.target.value);
    setAddText(e.target.value);
  };

  //handle save
  const handleSaveClick = () => {
    if (addText.trim().length > 0) {
      handleAddNote(addText);
    }  
  };

  return (
    <div>
      <textarea
        rows="8"
        cols="10"
        placeholder="Type here to add a note..."
        value={addText}
        onChange={handleChange}
      />

      <div>
        <p>200 characters remaining</p>
        <RiSave2Line onClick={handleSaveClick} />
      </div>
    </div>
  );
};

export default AddNote;

CodePudding user response:

by setting a variable

const small_id = unique_id.slice(0, 8);

you create a variable and assign it to each element of your initialState array's id. you should delete small_id and unique_id and do this:

const initialState = [{
    id: uuid().slice(0, 8),
    text: "1st note",
    date: "12/10/22022",
  }, {
    id: uuid().slice(0, 8),
    text: "2nd note",
    date: "15/10/22022",
  }, {
    id: uuid().slice(0, 8),
    text: "3rd note",
    date: "16/10/22022",
  }, {
    id: uuid().slice(0, 8),
    text: "4th note",
    date: "30/10/22022",
}];

In order to have different id (here you have always the same), or if the id isn't relevant for you you can always use the element's position in the array as key with the 2nd parameter of the map function like this:

<div className="notes-list">
  {notes.map((note, key) => (
    <Note key={key}  id={note.id} text={note.text} date={note.date} />
  ))}
<AddNote />

CodePudding user response:

The issue is your unique_id and small_id are only being generated once due to your function call syntax.

const unique_id = uuid();

Assigns unique_id the result of uuid(), rather than referencing the function. And therefore small_id is simply slicing the already generated uuid. To fix this your must generate a new uuid every time you create a note. Your can create a function that return a new 'small ID' everytime.

function genSmallID() {
 return uuid().slice(0, 8);
}

And now when you create your initial notes use the function:

const initialState = [{
    id: genSmallID(),
    text: "1st note",
    date: "12/10/22022",
  }, {
    id: genSmallID(),
    text: "2nd note",
    date: "15/10/22022",
  }, {
    id: genSmallID(),
    text: "3rd note",
    date: "16/10/22022",
  }, {
    id: genSmallID(),
    text: "4th note",
    date: "30/10/22022",
}];
  • Related