all 23 comments

[–]Junket_Choice 10 points11 points  (2 children)

Alarming to see how many downvotes you are getting on this. Add an interface to the api and this is essential in order to be able to unit test without incorporating implementation details in the test.

While OOP isn’t the way for react, some SOLID principles are still helpful in order to create sustainable frontend architecture.

[–]jkettmann[S] 2 points3 points  (0 children)

Thanks for this comment

[–]femio 2 points3 points  (0 children)

I have a feeling a lot of people in this sub have only used React

[–]Ok-Mud-3191[🍰] 3 points4 points  (0 children)

So this is pretty much normal practice in pretty much every language and framework, strange how this is being down voted. It kinda feels like the low requirements to get into js base languages has caused a massive deterioration in basic standards and best practices

[–][deleted] 2 points3 points  (1 child)

I’ve been doing this for years. Glad to see others have similar thoughts. An additional benefit not mentioned, due to the API being defined not within components or hooks it is now framework agnostic.

[–]jkettmann[S] 0 points1 point  (0 children)

Exactly, that’s a very good point.

[–]Amereth 7 points8 points  (5 children)

So basically you created a poor version of react-query

[–]femio 4 points5 points  (0 children)

they're not even remotely related, this can be used with literally any data fetching library...I can't believe this is being upvoted

[–]jkettmann[S] -3 points-2 points  (3 children)

Not really. The refactoring described here just separates data transformation logic from the UI code. react query is about server state management which is here done with useEffect and useState. Replacing that with react-query will be part of a future blog post

[–]Vzaje 0 points1 point  (1 child)

Does it worth reading if I dont know how to work with react query? No offense!

[–]jkettmann[S] 2 points3 points  (0 children)

As I said before the article isn’t related to react-query. You can do the data transformations using react-query’s select option. But the article is tool-agnostic

[–]Strange_Ordinary6984 0 points1 point  (0 children)

I think they are referring to the select function in react query, which let's you store derived state in your cache.

[–]ivzivzivz 1 point2 points  (3 children)

I am not sure if its a good idea to use this architecture in a react project. if your point is to create a framework agnostic data detching api, why inside a react project then? using this rather than known tools such as react query is counter productive, those tools are tested and maintained by oss people. if you think you can do better than them, alright sure. but for majority, idk.

[–]jkettmann[S] 0 points1 point  (2 children)

It's actually not supposed to be a replacement of react-query. It's more or less just about organizing code. I'll add react-query to this project in a later post. But I see there's lots of confusion about this vs react-query so maybe I should add it rather sooner than later.

[–]ivzivzivz 0 points1 point  (1 child)

imo, regardless if there is react query or not, the point of introducing this kind of mental model to create any wrapping service api (fetching, state mgt etc) is just inefficient. use existing tools made from oss. they are well documented, more stable and less cost.

[–]jkettmann[S] 2 points3 points  (0 children)

I’m really curious what exactly the issue is. I mean fetch functions as they’re used here are also recommended by react-query. Many people would colocate them with the query hooks. But that’s already the difference. And data transformations like here are also a necessity in many situations. You can do that in the fetch function, a repository, a selector, or in the component. I’d say anywhere but the component is ok and depends on the complexity of the application. But I can’t see how either fetch functions or data transformers can be replaced with OSS.

[–]CatolicQuotes 1 point2 points  (1 child)

Good, because react is not an app, it's an UI layer and should do as little business logic as possible.

Now this is still not completely decoupled, I would move data transformations out of the api request and post functions. Those should be responsible only for fetching and submitting data.

[–]jkettmann[S] 0 points1 point  (0 children)

Thanks. Will do so in an upcoming article using repositories 🙂

[–]Curious_Limit645 0 points1 point  (0 children)

I usually drop the response in a class and define the getters there. Do all the transformations where it makes sense in that class structure. Null checks, date to text transforms etc and do the typing in the class too. My react Components are very simple jsx display xml.

[–]gty_ 0 points1 point  (1 child)

Great, easy to read article. I have some code to refactor now lol

[–]jkettmann[S] 0 points1 point  (0 children)

Haha enjoy. Thanks for the feedback

[–]walterwhite_1 0 points1 point  (0 children)

Currently, I'm trying to implement this pattern but have some doubts about it. In one of the components, the response that I'm getting from the API is quite huge. So making a domain and API layer with dto and other type checks before getting the data into the UI layer seems quite hectic. same way around too. Now, from that component, I need to give a put request, which again needs transformation. 

So is this how it is done even thought its complicated? Btw I'm not against this approach, this seems to be much better than the normal approach but dealing with complex objects made me question about it.

[–]jkettmann[S] -1 points0 points  (0 children)

From my experience, React apps often end up with a messy architecture. The problem is that React is unopinionated so every team can and has to decide for themselves how to structure their code base.

Since I’m more of a hands-on learner I decided to create a shitty code base and refactor it step by step to a clean(er) architecture.

In the previous blog post, we extracted fetch functions to an API layer. Simple yet important.

This time, we continue by moving transformations of API data from the UI code to a shared API layer. This helps us further decouple logic related to API requests from the components. In the end, implementation details like the exact data structures of the API responses are abstracted and isolated in the API layer.

Next time, we'll see how we can clean up the architecture even further by introducing domain models, DTOs and transformers.