Let's talk about how React is only a view layer
Tags: react, typescript, redux
Published: 2020-07-26 05:08:00

Hello everyone,
This is a mix between discussion and a post, if you don't agree with me, I hope you write a comment and hopefully change my mind as long the point changes my views. I have recently done https://github.com/fossapps/Feature.Manager project, and I need a UI, I don't need UI to be fancy or production ready, I want it to be simple, and when I do decide to change I should still be able to make it production ready.

## Fetching from API

To fetch a data from API, I don't expect people to write `fetch` calls, they shouldn't be going to documentation and trying to find out how to make the call, what is the url, what parameter is going to be used etc. That's just a implementation detail which no one cares for, I want developers to invest time in actually building a product rather than stare at a API documentation, in the interest of saving developer's time, I always prepare/generate a API client.

I generally use swagger to document my API, and I generate clients for most of the language, however for typescript, I use `@crazyfactory/tinka`, this supports middleware, mocking, testing, caching etc, I haven't found anything which makes api calls better than this.

When I do need to make an API call, here's what I do:
```typescript
const api = Sdk.getInstance(baseUrl);
const response = api.profile.getById(userId);
if (isError(response)) {
  // do something
  return;
}
// use the actual response
```

And because everything is in typescript, I get full typescript features everywhere.

Now consumer of Sdk, never has to look at API documentation, just use your IDE, which shows what you need.

Normally for a large project where I want to ensure it's a very solid project, I create a separate package and use `semantic-release` to create releases automatically with proper semantic versioning, if you don't know what this is, have a look at semantic-release project.


But in my case, I just created a directory called Sdk and wrote everything there. Here's a PR which introduced it: https://github.com/fossapps/Feature.Manager.Ui/pull/27
If you follow that PR you'll notice that I'm using the tinka package, and adding Sdk methods, and because everything's typed, consumer of this Sdk, (which is this project itself), will never have to worry about what method it's using, what URL it's hitting etc. Now obviously I could generate a client using autorest, but I couldn't find a generator which supported middlewares (I'll need middleware support).

## Storing data (React is a View layer, don't fetch / store data in a view layer)
Now that fetching data is out of the way, let's talk about storing data.

I treat React as a view library, even though they're planning on introducing API calls with suspense soon.

One thing I really hate when I review someone's code, they simply go to `componentDidMount` (or `useEffect`), and make a api call, or they have hooks which makes the API call and put it on state.

IMO, this is a NO-NO, why would you access data from your view layer, have you ever queried a database from your view layer in any other MVC frameworks? Should you?

For that reason I've a different layer, I call it side effect layer, I use redux-saga for managing side effects this let's me keep my view and logic completely separate, in theory, if someone decided that I needed to ditch react for something else, in this situation I technically can, because again, React is just a view layer.

I keep data on redux and if say some day I happen to say I don't want to redux for data storage and want to move to mobx, I still can. They're not glued together.

Here's how I do this:
I've a page which needs data from API call, on it's componentDidMount (or useEffect, I'll come to this later), I check if I already have data available on store, if I do, then I don't do anything.

But if I don't have any data on store, then my componentDidMount will dispatch a action `SOME_DOMAIN/FETCH_DATA` (or something similar), it dispatches this, and my side effect layer notices this (redux saga has ability to listen to actions and call a method when it happens) on that call, I call API using the Sdk I mentioned before, and set the data on redux.

There's a side effect to this, how many times have you tried to do setState on a unmounted component? Say user goes to a page and immediately navigates away from that component, then you get a warning from react saying that's wrong, also you now can't re-use that data anymore, when user comes to the component, you make the api call again.

Because redux and redux-saga are different layers, that problem is not there anymore (and you can test your redux, redux-saga and your component separately, and writing tests are easier).

If you had done a fetch call inside a component, you'll end up with one messy component, and a very dreadful set of tests (worst if you decide to test after the code is done)

So I don't think you should keep data on your view layer, I also don't think you should make any calls from your view layer and I certainly don't think you should mix all of them on same layer.

The PRs I linked to, and the project I've linked to, neither of them is a gold standard, I know that, had I enough time, and had this project needed to be that way, I certainly would have spent a bit more time to separate Sdk into whole another npm package, same thing with components, I could have used a higher order component to give the color values and made the whole thing themeable, but that's not for today.

## Let's talk about redux hooks

I've seen people jumping on this hooks' train left and right, let's talk about redux hooks first.

When you `useSelector` on your component, you basically glue your component to redux, view layer and data layer is very tightly coupled, and that's not what you want in a production ready app, I personally don't even want it on a throw away app, is calling connect function really that difficult?

And I've heard this argument before, "How about we create a Wrapper component which calls the useSelector and passes them down to components which needs them", to that I say you just implemented `connect` component, it's basically the same, except you'll want to do it for every component, if not, it's just another `connect`.

And with redux hooks, now you have to mock your redux store, which is a whole other story.

Remember, you really don't want to glue your view and data layer. I keep the concerns separate, and when you do use redux hooks your component violates a lot of SOLID principles.

It certainly violates single responsibility principle, because it's now communicating with your redux layer,

It also violates open for extension and closed for modification principle, Now that you've used redux hooks, you can't extend it in anyway, you're actually tied to redux layer, and that's it. Take these two component for example:
```typescript
const Component: React.FC<IThemeProp> = (props) => {
  return (
    <div style={{padding: 10, background: props.theme.background, color: props.theme.color}}>{props.children}</div>
  );
};
export const Alert = withTheme(Component);
```
```typescript
export const AlertWithHook: React.FC = (props) => {
  const theme = useTheme();
  return (
    <div style={{padding: 10, background: theme.background, color: theme.color}}>{props.children}</div>
  );
};
```
The above examples are just simple react hooks, but let's take them as an example,

The first component which doesn't use hooks, can be extended easily, you can just use the component without the theme, and personalize it.

The second component however, is already tied with a certain context, and there's nothing you can do to change the second component with hook.

Another thing, the first component is a pure component (without the higher order component), for same input, it always returns same output, but the second one with hooks, isn't a pure component, it actually depends on what hook returns, which is a side effect, I generally tend not to go that way.

## Performance and functional vs classes
First off, I always prefer functional components for smaller components, if a component is getting big, probably time to break them down to smaller components.

Facebook also says, don't go and change your existing class components and change to functional, there's no need for that, (but people being people, have started rewriting libraries), I'm not doing that.

Another thing is people say with hooks, you get performance boost. I don't think that's the case, let me tell you why.

I think the hooks create another side effect which is all your components are functional, and functions are faster than classes, the performance boost isn't coming from hooks, but the fact that you have functional components.

What I prefer is to have smaller functional components, and when it comes to larger components which *might* have logic, or needs multiple handlers, I tend to have them as a separate method, after all, I can actually do OOO.

## Discussions welcome
I'm sure I might have missed some points, and there are so many things I wanted to communicate, but don't have the time to write about and don't want to extend the post too long.

Please raise your concerns in a way we can talk about, and if you don't agree, let me know why you don't agree, if you do, can you elaborate why you feel that way? I feel like there are some things my instincts tell me are dirty, but I can't actually explain them.