SkelDave
SkelDave

Reputation: 1186

React Duplicate Key Error

I'm getting the following error, I understand what its telling me but I can't figure out how to solve the issue.

flattenChildren(...): Encountered two children with the same key...

I have 2 lists on my page which contain emails. The initial state of my app contains the following data:

const initialState = {

  emails: [
    {
      id: 1, from: '[email protected]', body: 'test1 body', title: 'test 1 title',
    },
    {
      id: 2, from: '[email protected]', body: 'test2 body', title: 'test 2 title',
    },
  ],

  draggedEmails: [],

};

The UI of my app lets you drag and drop items from the first list (emails) to the second list (draggedEmails).

In my Redux reducer I have the following code to move emails between the lists.

  let newState = {};

  //Check if the email exists in my 'emails' array
  const doesExistInEmails = state.emails.find(x => x.id === action.id) !== null;

  //If it exists then move it to the 'draggedEmails' list
  if (doesExistInEmails) {

    const filteredEmails = state.emails.filter(e => e.id !== action.emailItem.id);

    newState = Object.assign(
      {},
      state,
      { draggedEmails: [...state.draggedEmails, action.emailItem], emails: filteredEmails }
      );

  } else {

    const filteredEmails = state.emails.filter(e => e.id !== action.emailItem.id);

    newState = Object.assign(
      {},
      state,
      { draggedEmails: [...state.emails, action.emailItem], emails: filteredEmails });
  }

  return newState;

The problem occurs when I move the items BACK to the emails list, once they have been moved to the 'draggedEmails' list.

The following code is what is used to create the elements and the keys.

createEmailItem(em) {
    return React.createElement(
      EmailItem, { email: em, key: `${em.id}` });
 }

Any help is appreciated,

Thanks.

EDIT: Console.Logged state after moving one item from the 'emails' list to the 'draggedEmails' list. Everything looks as it should.

Object {emails: Array[1], draggedEmails: Array[1]}

EDIT2: Adding render method.

render() {
    return (
    <div className="email-container" onDrop={this.onDrop} onDragOver={this.allowDrop}>
          {this.props.emails.map(this.createEmailItem)}
    </div>
    );
}

Upvotes: 0

Views: 11292

Answers (1)

SkelDave
SkelDave

Reputation: 1186

I found the problem. There were 4.

The first is that the following was returning 'undefined' rather than 'null'

const doesExistInEmails = state.emails.find(x => x.id === action.id) !== null;

The second is that my action doesn't have an id, my action has an emailItem which has an id

const doesExistInEmails = state.emails.find(x => x.id === action.emailItem.id) !== undefined;

The third is that I was filtering my emails rather than dragged emails in the following line.

const filteredEmails = state.filter(e => e.id !== action.emailItem.id);

And finally I was assigning the wrong values back when setting the state.

{ draggedEmails: [...state.emails, action.emailItem], emails: filteredEmails });

Should be...

{ emails: [...state.emails, action.emailItem], draggedEmails: filteredEmails });

So overall, I had lots wrong...

Thanks to the guys who commented.

Upvotes: 2

Related Questions