Skip to content

Immutability Revisited

Video Summary

  • In this module, we're going to tackle some of the gnarliest parts of React, things like memoization and the useEffect hook. To understand these notoriously-tricky things, it really helps to have a solid understanding of some of React's core mechanisms!
  • To help with this, I've created an interactive tool (included below) that shows how state is stored in the computer's memory, as we create and update stuff.
  • We have a single state variable, user, and it holds an object, { name: 'Ivy' }.
  • In plain JS, we could update the user's name by writing user.name = 'Ava'. But, that's a mutation! We're not supposed to mutate state in React.
  • In React, we do it by running setUser({ name: 'Ava' }).
  • Every time I do this, I create a brand new object, held in a unique spot in the computer's memory. I'm not editing the old { name: 'Ivy' } object, nor am I replacing the old object with the new one. For a short amount of time, at least, both objects will exist.
  • Each snapshot has its own user variable, and so we can think of it as two locally-scoped user variables that each point to a different object.
  • In practice, the JS garbage collector will sweep up old objects, so we don't have to worry about filling up the memory.
  • In JavaScript, objects are stored by reference. We can have two objects that appear identical, like { name: 'Ava' } and { name: 'Ava' }, but if we create them separately, they're distinct entities, like identical twins.
  • What if we have multiple state variables? For example, suppose we also have an items state variable that holds an array of numbers.
  • When we create new snapshots with setUser(), updating the user object, we reuse the items array.
  • Each snapshot will create a new items variable, but all of those variables will point to the same underlying array. We only have 1 array in memory, and it's being threaded through each snapshot.
  • This is important because it allows React to tell when a state variable has actually changed. We'll see the implications of this when we learn about useEffect and useMemo/useCallback.
  • Below, you'll find a sandbox that reproduces this visualization. You can log the values of all state values by opening the devtools and logging window.stateValues. Be sure to select the josh-bundler iframe before running any console instructions.

Here's the visualization from the video. You can reset the visualization to its initial state with the “” icon.

Computer Memory

state
Snapshot #1

And here's the sandbox from the video, showing how this works in code:

Code Playground

import React from 'react';

const INITIAL_STATE = { name: 'Ivy' };
window.stateValues = [INITIAL_STATE];

function App() {
const [user, setUser] = React.useState(
INITIAL_STATE
);

return (
<>
<button
onClick={() => {
const nextUser = {
name: generateNewName(),
};
setUser(nextUser);
window.stateValues.push(nextUser);
}}
>
Edit name
</button>

<div>{JSON.stringify(user, null, 2)}</div>
</>
);
}

const NAMES = [
'Kai',
'Ivy',
'Ava',
'Leo',
'Ada',
'Mae',
'Mia',
'Anna',
'Cal',
'Ram',
'Sri',
'Sai',
'Adi',
'Jay',
'Ren',
'Aoi',
'Ryo',
];

function generateNewName() {
return NAMES[
Math.floor(Math.random() * NAMES.length)
];
}

export default App;

What are these snapshots exactly?

In the demo above, I show “snapshots” which appear as cards containing pieces of state.

In this course, I use the term “snapshot” to mean the result of performing a render. It's a combination of two things:

  1. The specific values of any props/state at the time that the render occurred
  2. The React element(s) returned from the component, describing the UI calculated in the render.

My demonstration above doesn't show the elements, since we're focusing on state.

It might be worth reviewing the “Core React Loop” lesson from Module 2. We dig deeper into this idea!

You might also be wondering: What's the difference between snapshots and instances?

As we learned in the “Component Instances” lesson, a component instance is a JavaScript object that is the “source of truth” for everything related to a particular instance of a component. It's created when the component is mounted, and it persists until the component is unmounted.

A snapshot, by contrast, is not a specific JavaScript object. It's a more abstract/metaphorical concept. It refers to the data available at a moment in time.

So, we might say that an instance holds the true value of a piece of state, but every time that state changes, we create a snapshot that captures the current value of that state variable.

I realize that I've thrown a lot of terminology at you in this course: components, elements, instances, and snapshots. It's OK if these concepts aren't fully settled in your mind! Our goal is to slowly build confidence in our understanding, as we learn more and more about React.

The React docs can also help solidify things. Check out “State as a Snapshot”