The 5 most important takeaways from the new React Docs, for both newbie and experienced devs
Tags: react, javascript, useeffect, hooks
Published: 2023-07-19 03:57:14

---
title: The 5 most important takeaways from the new React Docs, for both newbie and experienced devs
published: true
description: 
tags: react, javascript, useEffect, hooks
cover_image: https://i.imgur.com/lHj9Ujh.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-07-18 17:21 +0000
---

The new React documentation is incredibly well written and is a great starting point to understand how React works under the hood. This is great if you're a beginner learning this framework for the first time, but in my opinion it's also a useful resource for more experienced developers trying to solidify their knowledge.

If you have a few hours to spare, my recommendation is that you go check out the [documentation](https://react.dev/learn/describing-the-ui) yourself. But if you don't, here are the 5 most valuable nuggets of knowledge I was able to take away from the notes I took as I read the new React docs:


### 1.- Understanding the React render
Understanding React rendering is crucial to creating well-written components that are performant. Let's remember that (functional) components are simply JavaScript functions that return JSX and are called by React to display that as HTML on the page.

**Rendering happens when React calls a component function and its JSX is transformed into a React element so it can then be added to the virtual DOM.** During the rendering phase, React will also compare the updated virtual DOM with the old one (diffing) to decide which nodes need to be changed in the real DOM.

Since the component function is called during the render phase, every statement or expression found in that function's body will also be evaluated again. 

Commiting occurs when the updated component has been rendered (the function was called) and now it can be copied to the browser DOM if any changes were found. After the DOM is updated, the browser repaints the screen.

**What triggers a render?**
-The initial mounting of a component
-The state of the component changed
-The props of the component changed
-A parent component re-rendered
-A re-render was manually triggered

*Based on these rules, we can infer that re-rendering a component higher in the tree could cause a large portion of the component tree to re-render, if they are descendants of this component. We can solve this "rendering cascade" by wrapping our components with React.memo, but we should not over-optimize unless it's really necessary. React is "fast" by default.

*Let's keep in mind that a component's state persists throughout re-renders, so we can be sure that the state of a component will remain the same if the render was triggered by anything other than a state change in that component. Changing props will not change the state even if a prop is used to initialize a piece of state.

*Another thing to keep in mind is that React only commits changes to the real DOM if there is a difference between renders. This means that a component can re-render without commiting anything new to the DOM. Still, if a component performs an expensive calculation in its function body and React re-renders it, it could still block the UI even if no changes were committed to the DOM. That's why we need to be careful about not triggering unncessary re-renders, or keeping expensive calculations in components to a minimum.

Read more about this in the [React docs.](https://react.dev/learn/render-and-commit)

---

### 2.- State as a snapshot
The most important thing to take away from this is: 
**A component's state is tied to each render cycle and won't change until the next render.**

We can think of a component's state as a snapshot of a value in React's memory, and any operation or expression that uses state in the component will use this snapshot. 

If we want to 'change' the snapshot, we have to change the value in memory (using a state setter function). This will in turn call the component function with a new snapshot (re-rendering), effectively using the new value both in the function body and its JSX.

I used to struggle with this logic as a newbie React dev, because I was always thinking "how can I await for the state to be updated so I can then trigger some other action that uses the new state?". This led me to believe that anything that 'reacted' to state changes needed to be wrapped in a useEffect, since it was the only way to ensure the state had been updated. In reality, this often leads to components with tons of performance issues and unnecessary re-renders. 

**You can be sure that every part of the component function that uses state will have the latest snapshot** (unless you have created a closure somewhere, like a callback in a setTimeout). Setting state does not change the variable in the existing render, but instead requests a new render.

Read more about this in the [React docs.](https://react.dev/learn/state-as-a-snapshot)

---

### 3.- Don't use props to set state unless you want to ignore all further updates to said prop

The most important thing to remember here is: 
**If you are passing a component's piece of state as props to a child component, don't use that value to initialize state in the child component.**

Why? Because state initialization occurs only when the component is mounted (it's rendered for the first time). This means that any updates to the parent's state won't trigger a state update in the child, effectively creating two independent states that will be out of sync. This is okay if you don't expect changes in the parent to be reflected in the child, but the majority of times we do.

If your intention is to keep a component in sync with its parent, then your child component should be a controlled component (it doesn't keep its own state). You can then use the value of the prop anywhere in your component, being sure that state updates in the parent will reflect correctly in the child.

Read more about this in the [React docs.](https://react.dev/reference/react/useState)

---

### 4.- You need useEffect less thank you think
As I mentioned earlier in this post, useEffect tends to be overused by beginner React developers to trigger something in response to a state change. 

State, props and JSX are the only key elements to building reactive component trees in React, and effects are simply designed as a way to step out of this paradigm to perform a 'side effect'. These side effects are usually actions that interact with some type of external system, not the application itself. Actions to be performed with effects include making an API call, controlling a non-React component, triggering some browser action, adding event listeners to non-React elements in the DOM, etc. 

Here are some examples of common tasks where useEffect is not necessary:

* **Transforming state or props before displaying them**

Most poorly written effects that I've seen are used to 'listen' to changes in a piece of state to then calculate a new state variable from it.

```
const PoorlyWrittenComponent = () => {
  const [data, setData] = useState([]);
  const [sortedData, setsortedData] = useState([]);

  useEffect(() => {
    fetchData();
  }, []);

  useEffect(() => {
    const sorted = [...data].sort((a, b) => {
     if (a.name > b.name) return 1;
     else if (a.name. < b.name) return -1;
     return 0;
    });
    setSortedData(sorted);
  }, [data]);

  const fetchData = async () => {
    // Data fetching
  };

  return (
    <div>
      <h1>Transformed Data Example</h1>
      {sortedData.map((item) => (
        <div key={item.id}>
          <h3>{item.name}</h3>
          <p>{item.description}</p>
        </div>
      ))}
    </div>
  );
};
```

Remember that all expressions and assignments in a component are evaluated again with each re-render. If we keep this in mind, it becomes clear that we can transform state by simply creating a new variable and assign it the expression that transforms the state. The expression will always use the latest state (see State as a Snapshot above). We can then use this variable in our JSX:
```
const GoodComponent = () => {
  const [data, setData] = useState([]);
  const sortedData = [...data].sort((a, b) => {
     if (a.name > b.name) return 1;
     else if (a.name. < b.name) return -1;
     return 0;
  });

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    // Data fetching
  };

  return (
    <div>
      <h1>Transformed Data Example</h1>
      {sortedData.map((item) => (
        <div key={item.id}>
          <h3>{item.name}</h3>
          <p>{item.description}</p>
        </div>
      ))}
    </div>
  );
};
```


* **Completely resetting the state when a prop changes**

Let's say we pass a userId prop to a component to keep track of which user is being represented by the component. If we change the user represented in the component, we want to remove all current state and give the component a clear slate of state. To avoid unnecessary effects and re-renders, we can represent the userId that owns that component by also passing the userId as a key prop. Whenever a key changes in a component, we are requesting React to mount a different instance of that component with the new key.
```
const ParentComponent = ({ id }) => {
  const [selectedId, setSelectedId] = useState(id);

  const handleIdChange = (newId) => {
    setSelectedId(newId);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <button onClick={() => handleIdChange('newId')}>Change ID</button>
      <ChildComponent key={selectedId} id={selectedId} />
    </div>
  );
};
```

* **Responding to a change triggered by an event handler**

Effects are often used to perform actions in response to a user action. In the next example, clicking on a submit button runs an event handler function that changes the state of isSubmitted and triggers an effect that displays a notification to the user.
```
const NotificationComponent = () => {
  const [isSubmitted, setIsSubmitted] = useState(false);

  useEffect(() => {
    if (isSubmitted) {
      // Display notification to the user
    }
  }, [isSubmitted]);

  const handleSubmit = () => {
    setIsSubmitted(true);
  };

  return (
    <div>
      <h1>Notification Example</h1>
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
};
```

The useEffect in this piece of code is unnecessary, and we can simplify it by putting the code that displays the notification in the event handler.
 
```
const NotificationComponent = () => {
  const [isSubmitted, setIsSubmitted] = useState(false);

  const handleSubmit = () => {
    setIsSubmitted(true);
    // Display notification to the user
  };

  return (
    <div>
      <h1>Notification Example</h1>
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
};
```
If a change in the component is triggered by an action from user input, it's better to handle all the logic related to the event in the event handler. In other cases, it makes sense to trigger some action in response to the component rendering, like sending a request to log data and analytics when the page is visited. 

When deciding whether to put some behavior in an effect or in an event handler, think about what kind of logic it is from the user's perspective. If the action is performed as a result of user input, leave it inside the event handler. If it's performed as a result of the user *seeing* the page or the component, it might make sense to put it in an effect. 

Read more about this in the [React docs.](https://react.dev/learn/you-might-not-need-an-effect)

---

### 5.- Create custom hooks to reuse stateful logic in multiple parts of your application

Custom hooks are abstractions over built-in React hooks to keep track of a piece of state or trigger effects without displaying the implementation in the component directly. This helps you reuse a certain stateful logic in several components.

Be aware that built-in React hooks and custom hooks can only be called from the top level of React component functions or other custom hooks. A custom hook's name must always start with the word 'use'.

Custom hooks typically return a value that we want to keep track of. They behave similarly to components in the sense that state changes in the hook will cause it to re-render and therefore return the value again. You can think of custom hooks as components that return a value instead of JSX.

Here is an example of a custom hook that keeps track of a count that is incremented every second. The initial value and the value to increment the counter by are passed when initilializing the hook:

```
const useCounter = (initialValue, incrementBy) => {
  const [count, setCount] = useState(initialValue);

  useEffect(() => {
    const interval = setInterval(() => {
      setCount((prevCount) => prevCount + incrementBy);
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, [incrementBy]);

  return count;
};
```

We can then use this hook in other components, abstracting the implementation of the counter and allowing us to simply use the value in the JSX:

```
const CounterComponent = () => {
  const count = useCounter(0, 1);

  return (
    <div>
      <h1>Counter: {count}</h1>
    </div>
  );
};
```
Read more about this in the [React docs.](https://react.dev/learn/reusing-logic-with-custom-hooks)

I hope you found some of this information useful. Let me know what were your main takeaways after reading the new React documentation. It's always a great feeling to have a stronger understanding of your frontend framework of choice, and I'd love to hear what you have learned.