React 102 - Basic data flows
Tags: react, javascript, beginners, tutorial
Published: 2022-11-16 00:50:08

So, you’ve learned the basics of React, then when you finally started using you started falling for one pitfall after another. Well, you’re in the right place... finally!

Few things:

- This is not to be a comprehensive guide
- It is not for those just learning (hence 102 and not 101)
- Also, I might take some generalizations for the sake of simplicity
    - as you may know… JS is weird!
- Finally, I’ll pretend class components don’t exist and so neither should you.
    - I’m not saying you never should learn them, but today… not at the 102 level.

If you do want to learn from zero, I recommend checking out the [Beta React Docs](https://beta.reactjs.org/learn), you’ll learn things there that many people using it for quite a while don’t know (really!).

Finally, feel free to ask anything you might be having problems with. I love to help! (It might also help me find things to write, so win-win-win.)

---

## Lifecycle and data flows

One of the biggest enemies of those starting React is to render stuff on the screen and have it change.

### The basic render

```jsx
function BasicRender(){
  return (
    <div>I'm rendering!</div>
  )
}
```

This will just render whatever is in the JSX.

### With props

```jsx
function WithProps({counter}){
  return (
    <div>The counter is: { counter }</div>
  )
}
```

First thing is that I’m [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) the props value.

This will render at `{ counter }` whatever the counter value is. And every time it gets a new value, it will render the new value.

In this case, there are two things to know/remember:

1. React shallowly compares to check if the component should rerender or not.
2. The difference between [primitives](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) and non-primitives.

Knowing that you would know that primitives are checked by their value while everything else is checked by their reference.

### With split flows

```jsx
function WithIf() {
  const random = Math.random();

  if (random > 0.5) {
    return (
      <div>Random is big!</div>
    );
  } else {
    return (
      <div>Random is small!</div>
    );
  }
}
```

`if` works just as you expect, there are rules about hooks where you can’t initiate them inside split flows ([you can only use them at the top level of the component](https://beta.reactjs.org/learn#using-hooks)), but after that, it works just like that.

### With state

```jsx
function WithState() {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <div>The counter value is: { counter }</div>
      <button onClick={() => setCounter(counter + 1)}>Click me!</button>
    </div>
  )
}

function WithVariable() { // ???
  let counter = 0;

  return (
    <div>
      <div>The counter value is: { counter }</div>
      <button onClick={() => counter += 1}>Click me!</button>
    </div>
  )
}
```

First things first: the second approach, with variable, will not work. 

Why? The short answer is that React needs a hook to know that something changed in order to rerender. This happens because functional components are [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) and while it will indeed change the value internally, React will never know when to rerender the component and when it does rerender it will recreate it at the `0` value.

So, why does the first approach works? That’s the React magic, and for now, you should just accept it and what you can do with it.

Remember about the props? That also applies to the state.

Non-primitives like objects or arrays, if you simply change the value inside and return the object, this means that the reference doesn’t change, even if you use the `setState` function.

The right way to think is that you always need to return a new reference, this means:

```jsx
const newArr = [...oldArr];
const newObj = {
  ...oldObj
};

// spreading itself doesn't create new references
// but the container you're spreading it into is a new reference.
```

### With effects

```jsx
function WithEffect1() {
  const [state, setState] = useState('initial state');

  useEffect(() => {
    setState('useEffect []');

    const timeout = setTimeout(() => {
      setState('useEffect [] > timeout');
    }, 500);

    return () => {
      setState('useEffect [] > return');
      clearTimeout(timeout);
    };
  }, []);

  return (
    <div>{state}</div>
  );
}

// you might see below duplicated, probably with the return,
// but in dev mode, it's the Strict Mode
// also, the initial state you'll never see in this situation
// because react is really fast

// If you slowed time down, you might see this happening:
/**
 * initial state
 * useEffect []
 * ~500 ms~
 * useEffect [] > timeout
 */
```

This is the most basic use of `useEffect`. (Think of the `setTimeout` as a `fetch` call.)

Usually, we have more things going on, for example:

```jsx
function WithEffect2() {
  const [state, setState] = useState('initial state');
  const [otherState, setOtherState] = useState(0);

  useEffect(() => {
    setState('useEffect [otherState]');

    const timeout = setTimeout(() => {
      setState('useEffect [otherState] > timeout');
    }, 500);

    return () => {
      setState('useEffect [otherState] > return');
      clearTimeout(timeout);
    };
  }, [otherState]);

  return (
    <div>
      <div>{state}</div>
      <button onClick={() => setOtherState(otherState + 1)}>
        Change the Other State
      </button>
    </div>
  );
}

/**
 * initial state
 * useEffect [otherState]
 * ~500 ms~
 * useEffect [otherState] > timeout
 * ~click~
 * // batched update, you'll never see the return
 * [useEffect [otherState] > return | useEffect [otherState]]
 * ~500 ms~
 * useEffect [otherState] > timeout
 */
```

In this one there are more things happening.

But the idea is that the `initial state` will always be rendered first, regardless.

Then any and all `useEffects` will render the very next tick.

Anything that’s asynchronous like `promises` or `fetches` calls will render so soon they finish.

Return statements inside the `useEffect` trigger before the next calculation when they are triggered.

Usually, you have a state that will be rendered first (usually you’ll render as a nullish value using a `if` to render a `Loading...` or something like this). Then the `fetch` will start, finish and set a new state, that will trigger a render, now with the values.

One thing to take care is that if you put in the `dependency array` the very `state` you’re mutating in the `useEffect`, unless you have some check before, you’ll probably trigger an infinite recursion:

```jsx
// this will break your page!
useEffect(() => {
	// add some exit condition if you really need to do this
  setState(state + 1);
}, [state])
```

### Bonus: derived state

```jsx
function DerivedState({ myValue }) {
  const [state, setState] = useState(0);
  const [secondState, setSecondState] = useState(0);

  useEffect(() => {
    setState(myValue * 2);
  }, [myValue]);

  useEffect(() => {
    setSecondState(state * 2);
  }, [state])

  return (
    <div>
      <div>{state}</div>
      <div>{secondState}</div>
    </div>
  );
}

function DoThisInstead({ myValue }) {
  const stateToRender = myValue * 2;
  const secondState = stateToRender * 2;

  return (
    <div>
      <div>{stateToRender}</div>
      <div>{secondState}</div>
    </div>
  );
}
```

Things like this are common. If you already have the value, you don’t need to put it inside a `state` and use `useEffect` to change it.

The way it’s been done in the first example you’ll see a cascade happening every time `myValue` changes and it might have unintended consequences.

If it comes from `props`, you can just calculate from it, when it changes, it will recalculate automatically.

If you’re doing something like a `filteredItems` from some `fetch`, same thing. The `useEffect` will save to the `state` the values, then you just use a `const filtered = state.filter()`.

Every time `state` changes, so will the filter. If you need, you can always [`memo`](https://beta.reactjs.org/apis/react/useMemo) the values.

---
[Example deployed](https://react102-noriller.vercel.app/)

[GitHub of the Project](https://github.com/noriller/react102)

Again: questions? Just ask! (And to not be ignored… read this helpful [“how to ask a good question”](https://stackoverflow.com/help/how-to-ask))

And… question for YOU! Where are you having trouble with React? 

---

Cover Photo by [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/flow?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)