New data model/API layer #793
Replies: 3 comments 1 reply
-
My issues with
|
Beta Was this translation helpful? Give feedback.
-
Proposal 1Here's my proposal for what an alternative might look like. Let's call it "Proposal 1". 😊 OverviewMy proposal sorts code into three layers.
Feature: Object-oriented designThe model and source layers are designed according to object-oriented principles. For example, when creating a model that needs to be able to interact with the API, it's passed an API adapter object, e.g. (pseudo-code): //...
const apiClient = new BrowserAPIClient();
const campaignApi = new CampaignApiAdapter(apiClient);
const campaignsModel = new CampaignsModel(reduxStoreAdapter, campaignApi);
const campaigns = await campaignsModel.getActiveCampaigns(); This design is powerful because it makes it very easy to replace the Benefits
Feature: Redux comeback (for all state)I'm suggesting that we bring back redux for the storage of data. The models would then use redux actions and the redux store to modify and provide data.
This allows us to use all of the developer tooling that redux provides, and to also have a central storage for all data which is very useful to achieve things like updating data in one part of the system based on what happens elsewhere, without strong coupling, e.g. updating the breadcrumbs when the name of something changes, or updating the row of a view when a tag is applied to a person. The store would contain "bare objects", and the models would use (or just return) the data from those objects. For example, a Benefits
Caching in the modelsWe swapped to react-query from redux because we wanted to think of the local representation of server data more like a cache. But that doesn't mean we have to use a caching library. We can still store the data in redux, and do caching in the models. If a model has a In most cases we will be able to reuse the same (simple) code for this. But in some cases we will want more complex caching logic, and with this approach that will be quite simple, because that code will be self-contained within the model class. Benefits
Simple React SuspenseThe model layer can very easily implement the necessary logic to use React Suspense for handling asynchronously available data, showing loading spinners etc. Granted, I've never implemented Suspense like this before, but I'm pretty sure it should be possible to do this: const Container = () => {
// Not sure how connecting to models would work, but something like this?
const campaignModel = useModel(CampaignModel, 25);
useEffect(() => {
// On first render, start loading the campaign
campaignModel.load();
});
return (
<React.Suspense fallback={ <Spinner /> }>
<CampaignCard campaignModel={campaignModel} />
</React.Suspense>
);
}
const CampaignCard = ({ campaignModel }) => {
// This will fail and cause suspense if not loaded yet
const data = campaignModel.data;
return (
<h1>{data.title}</h1>
);
}
class CampaignModel {
private _promise: Promise<CampaignData> | null;
private _data: CampaignData | null;
constructor(store: ReduxStoreAdapter, api: ApiAdapter, id: number) {
super(store, api);
this._id = id;
this._data = null;
}
async load() {
// TODO: Caching
this._promise = this._api.loadCampaign(this._id);
// TODO: The data should actually go in the redux store, not just end up here
this._data = await this._promise;
}
get data(): CampaignData {
if (!this._data) {
// Throw promise to trigger React Suspense
throw this._promise;
}
return this._data!;
}
} In conclusionThis approach separates code into three concerns:
In doing so, I believe that we will get more testable and scalable code, and whatever increase in boilerplate we incur will be manageable through object-oriented patterns for code reuse. Eager to get feedback, here or elsewhere. 😊 |
Beta Was this translation helpful? Give feedback.
-
This was implemented, caused a number of issues, and was then ditched in favor of a variation where normal react hooks replace the model and repo (adapter). |
Beta Was this translation helpful? Give feedback.
-
I'm writing this to start a discussion on whether we should replace/augment
react-query
with something else.We have been using
react-query
as the main data/network layer for a while now, and put a lot of effort into making it nice to use and not have a lot of boilerplate. Throw mostly the work of @djbusstop we have created a mostly nice to use abstraction layer with custom hooks.All in all, however, I don't think it's working great.
In this discussion I'm going to first post the issues I have with react-query, and then some ideas I have for alternative solutions.
Beta Was this translation helpful? Give feedback.
All reactions