The paradigm of React
Tags: react, declarative, webdev, tutorial
Published: 2023-09-18 09:02:49

I think it may be important to know one of the top principles of React, because without it, the code may turn out a bit non-idiomatic React, and it may need refactoring to bring it back to the React Way.  This one major principle is: use declarative ways to write your components.

Sometimes, it may need to be imperative, but those are supposed to change a state, so that the state can change into something you declared earlier.

For example, you may say that, when you have an array, you show the list as:

```jsx
<ul>
  {arr.map((e, i) => <li key={e.id}>{e.title}</li>)}
</ul>
```
So you are declaring: with the `arr`, what should the output be.

Now again, if you have filtering of the items, if the user can enter a keyword, then the code becomes:

```jsx
const filteredArray = arr.filter(e => e.title.includes(keyword));

return (
  <ul>
    {filteredArray.map((e, i) => <li key={e.id}>{e.title}</li>)}
  </ul>
);
```
You may not need to use `useMemo` for the `filteredArray`. However, imagine if you have a case where, if the user types in keyword, and needs to click on the "Filter" button to do the filtering, then you don't want to do the costly filtering for every user keypress. So if your code causes the main component to re-render every time when there is a keypress, then you may want to use the `useMemo` to do the filtering, depending on what `keywordConfirmed` is, when the user clicks on the "Filter" button. (There is a way to let a sub-component not cause the main component to re-render on each user keypress, so the filtering won't be done every time, but it is beyond the scope of this post).

There is also this idea that: if the slowest computer and smartphone can handle your task of filtering every time in a super fast way, then, you may not need to use `useMemo`.  Optimize it only when it is necessary. Note that this is different from the LeetCode way, when `n` can be 5 million or 5 billion. Here, `n` could be 50 in your use case, or 500, so optimizing in such cases can be viewed as premature optimization. (Donald Knuth: "The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.")

Now what we have so far are all declarative: when `arr` is such, and `keyword` is such, then the output will be such: meaning it is like a function: what goes in, what goes out, and it is functional, or declarative. If you are familiar with the programming language Lisp, that's how it works.

One note about this: when you consider the states, in general, try to have as few of them as possible. Also, look at what needs to be the state, and what are values that can be derived from the state. For example, in the example above, `arr` is the state, and `filteredArray` can be derived from it. So don't make `filteredArray` a state, but make it a local, derived value inside this functional component.

We also use these states and write the rest of the component using them.  For example, we may have

```jsx
  {arr === null && <div>Loading...</div>}
```
and it is again, declarative.

Now there are times we need to do imperative operations, such as to fetch the value when the component is first rendered. (it could be this component or a higher up component).

To do that, it'd be

```jsx
useEffect(() => {
  fetch(url)
    .then(res => res.json())
    .then(data => setArr(data))
    .catch(console.error);
}, []);
```
So here, we fetch data from the server, and set it to the `arr` state. And from here, everything becomes declarative again.

The same with event handlers. You'd usually write the handler to change one or more states, so that the declarative code will handle the rest.

The rule is: usually it is either the user doing something, or the network sends back some data, or `setTimeout`, `setInterval` triggers some change, and therefore changes the state. From that point on, the declarative mechanism handles the rest.

In other words, it is events: user interactions, timer events, network events, that change the states, and then from there, everything is handled in a declarative way. That is: you don't have to do anything.

This concept is important, because if you use React, and you write it without thinking mostly declarative, and use both declarative and imperative ways, then your React code will not idiomatic and it may be against the overall paradigm that React is using.

Example: 
https://codesandbox.io/s/funny-hugle-94j2cj?file=/src/App.js

Reference: https://react.dev/learn/managing-state
Note that there are seven sections for this topic.