TheOdinProject / top-meta

TOP hub for ongoing support and improvement of the curriculum by the maintainers
31 stars 10 forks source link

React Revamp: Keys In React Lesson #236

Closed Michaelleojacob closed 1 year ago

Michaelleojacob commented 1 year ago

Introduction

How to use keys in React effectively.

Lesson Overview

by the end of the lesson you should be able to answer the following:

What are keys?

When rendering a list, keys are strings used to help React keep track of which item(s) in the list have changed, are added, or are removed.

Rules for using keys

When is it ok to use index as a key?

What to avoid or watch out for when using keys

Examples

Ideal situation.

Iterating over a list of objects that have a unique identifier.

Best practice would be to add a unique ID when the item is created.

// In this example lets say when someone creates a new todo, the todo constructor adds `id: uniqid()`
const todos = [
  { task: 'mow the yard', id: '1j32b51bk' }, // `id: uniqid()` on todo creation
  { task: 'Work on Odin Projects', id: '41hgi12gi' },
  { task: 'feed the cat', id: '12ih412b412b4' },
];

// here we are using the already generated id as the key.
const iterateTodos = todos.map((todo) => <div key={todo.id}>{todo.task}</div>);

function TodoList() {
  return <div>{iterateTodos}</div>;
}

Better than plain index.

When working with an array of primitive values, we wont have a unique id property to pass to key. One idea that would work better than just using index as the key would be to concatinate array[index] + index as this is more likely to be a unique value.

const todos = ['mow the yard', 'Work on Odin Projects', 'feed the cat'];

const iterateTodos = todos.map((todo, index) => (
  <div key={`${todo}_${index}`}>{todo}</div>
));

function TodoList() {
  return <div>{iterateTodos}</div>;
}

Using index correctly

If a list will never be modified or stictly manipulated by push() + pop() we can use index.

const months = ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

function MonthList(){
    return (
        <ul>
            {months.map((month, index) => (<li key={index}>{month}</li>))}
        </ul>
    )
}

const

bad

this approach will cause a complete re work of every list item any time one changes.

// !! this will cause the entire list to be destroyed and be re-created every render! !!
const todos = [
  { task: 'mow the yard' },
  { task: 'Work on Odin Projects' },
  { task: 'feed the cat' },
];

const iterateTodos = todos.map((todo) => (<li key={uniqid()}>{todo.task}</li>));

function TodoList() {
  return <ul>{iterateTodos}</ul>;
}

Also bad

This will cause unintended behavior when modifying, or filtering array element positions. Considering that todos would likely be updated, changed, filtered or etc, we would NOT want to use index as our key.

const todos = ['mow the yard', 'Work on Odin Projects', 'feed the cat'];

const iterateTodos = todos.map((todo, index) => (<div key={index}>{todo}</div>));

function TodoList() {
  return <div>{iterateTodos}</div>;
}

Assignment

Read this article: how to use correctly use keys with examples demonstrating preformance and re-renders.

Short video demonstrating Index as Key being an Anti-pattern

Knowledge Check

Additional Resources

React Beta Docs