# motivation
We think we need a react framework and server-side rendering (SSR) because that's where money is being made. If we are building a highly dynamic and interactive web application then we probably don't need SSR. These frameworks sell us that they are an easier way to build web apps, but that's not true. Just think of it this way: if we can build a web app using only static assets, isn't that simpler than having static assets and a react framework server?
React hook-based fetching and caching libraries dramatically simplify data synchronization but are so tightly coupled to a component's life cycle that it creates waterfall fetches and loading spinners everywhere. We also have the downside of not being able to normalize our cache which means we have to spend time thinking about how and when to invalidate our various caches.
Further, all of these data caching libraries don't handle data normalization. In every library we are going to see a line similar to this: "Data normalization is hard and it isn't worth it." Their libraries are not built with data normalization in mind so they claim it's an anti-feature. Why do we want to normalize data in the backend but not the frontend? Data normalization is critically important because it makes CRUD operations automatically update our web app without having to invalidate our cache just so the app will refetch the data we already have.
So what if we are building a highly interactive web app that doesn't need SEO and we also need more control over data synchronization and caching?
Are you frustrated by the following issues in your react app?
- Prop drilling
- Waterfall fetching data
- Loading spinners everywhere
- Extraneous network calls
- Business logic tightly coupled to react component lifecycle hooks
- State management boilerplate
- Lack of state management
- Lack of async flow control tooling
We built starfx
because we looked at the web app landscape and felt like there
was something missing.
The benefits of using this library:
- Designed for single-page applications (SPAs)
- Makes data normalization easy and straightforward
- Has a powerful middleware system similar to express to handle requests and responses
- Reduces state management boilerplate to its absolute essentials
- Has a robust side-effect management system using structured concurrency
- Has data synchronization and caching separated from react
# when to use this library?
The primary target for this library are SPAs. This is for an app that might be hosted inside an object store (like s3) or with a simple web server (like nginx) that serves files and that's it.
Is your app highly interactive, requiring it to persist data across pages? This
is the sweet spot for starfx
.
This library is not a great fit for ecommerce, tiny projects, or blogs. This is for web apps that are generally behind a login screen that require a desktop-class user experience. This library is designed to scale, so it might feel a little overwhelming. Just know if you use this library, your code will be easier to read, easier to write, all while handling a massive amount of business complexity.
# code
Here we demonstrate a complete example so you can glimpse at how starfx
works.
In this example, we will fetch a github repo from an API endpoint, cache the
Response
json, and then ensure the endpoint only gets called at-most once
every 5 minutes, mimicking the basic features of react-query
.
1import { createApi, createSchema, createStore, mdw, timer } from "starfx";
2import { Provider, useCache } from "starfx/react";
3
4const [schema, initialState] = createSchema();
5const store = createStore({ initialState });
6
7const api = createApi();
8// mdw = middleware
9api.use(mdw.api({ schema }));
10api.use(api.routes());
11api.use(mdw.fetch({ baseUrl: "https://api.github.com" }));
12
13const fetchRepo = api.get(
14 "/repos/neurosnap/starfx",
15 { supervisor: timer() },
16 api.cache(),
17);
18
19store.run(api.bootup);
20
21function App() {
22 return (
23 <Provider schema={schema} store={store}>
24 <Example />
25 </Provider>
26 );
27}
28
29function Example() {
30 const { isInitialLoading, isError, message, data } = useCache(fetchRepo());
31
32 if (isInitialLoading) return "Loading ...";
33
34 if (isError) return `An error has occurred: ${message}`;
35
36 return (
37 <div>
38 <h1>{data.name}</h1>
39 <p>{data.description}</p>
40 <strong>๐ {data.subscribers_count}</strong>{" "}
41 <strong>โจ {data.stargazers_count}</strong>{" "}
42 <strong>๐ด {data.forks_count}</strong>
43 </div>
44 );
45}
# install
1npm install starfx
1yarn add starfx
1import * as starfx from "https://deno.land/x/starfx@0.7.0/mod.ts";