DEV Community

Ramu Narasinga
Ramu Narasinga

Posted on

State management in Twenty codebase - Part 1.2

Inspired by BulletProof React, I applied its codebase architecture concepts to the Twenty codebase.

This article focuses only on the state management in Twenty codebase.

Why learn this pattern?

Let’s be honest, your useState code is probably a mess. Mine was too.

Look, we’ve all written this:

const [websites, setWebsites] = useState([]);
Enter fullscreen mode Exit fullscreen mode
const addWebsite = async (data) => {
  const newWebsite = await api.post('/websites', data);
  setWebsites([...websites, newWebsite]); 
};
Enter fullscreen mode Exit fullscreen mode

We all start the same way, useState for everything. Throw in Context API when passing props gets annoying. Works fine until your app grows.

Then you’re debugging why:

  • Your app is slow because state is everywhere

  • The UI shows old data after mutations

  • Clicking fast causes weird race conditions

  • You have to manually refresh data in 10 places

Production apps like Twenty don’t have these problems because they use different patterns.

Let me show you what I learned from studying their code.

Prerequisite

  1. State management in Twenty codebase — Part 1.0

  2. State management in Twenty codebase — Part 1.1

Approach

The approach we take is simple:

  1. Pick a route, for example, {id}.twenty.com/settings/billing

  2. Locate this route in Twenty codebase.

  3. Review how the state is managed.

  4. We repeat this process for 3+ pages to establish a common pattern, see if there’s any exceptions.

In this part 1.2, you will learn about the state management in the settings/billing route for a workspace. We will find out what libraries Twenty used, how the files are structured, how the data flows to manage its state.

I reviewed the billing route and I found that the following components give us a clear picture about the state management.

  1. SettingsBilling.tsx

  2. SettingsBillingContent.tsx

SettingsBilling.tsx

In this SettingsBilling.tsx component, currentWorkspace and isPlanLoaded are defined as shown below:

const currentWorkspace = useAtomStateValue(currentWorkspaceState);

const { isPlansLoaded } = usePlans();
Enter fullscreen mode Exit fullscreen mode

Twenty uses Jotai to manage its state. Learn more about Jotai. We also reviewed this useAtomStateValue briefly in part 1.1.

If there is current workspace and isPlansLoaded, then SettingsBillingContent is shown

{currentWorkspace && isPlansLoaded ? <SettingsBillingContent /> : <></>}
Enter fullscreen mode Exit fullscreen mode

usePlans.ts

import { useQuery } from '@apollo/client/react';
import { ListPlansDocument } from '~/generated-metadata/graphql';
import { isDefined } from 'twenty-shared/utils';

export const usePlans = () => {
  const { data, loading, error } = useQuery(ListPlansDocument);

  const isPlansLoaded = isDefined(data?.listPlans);

  const listPlans = () => {
    if (!data) throw new Error('plans is undefined');
    return data.listPlans;
  };

  return { loading, error, isPlansLoaded, listPlans };
};
Enter fullscreen mode Exit fullscreen mode

usePlans.ts is a hook that fetches the plans and it returns the isPlansLoaded.

SettingsBillingContent.tsx

In the SettingsBillingContent.tsx, the following are defined:

  1. SettingsBillingSubscriptionInfo

  2. SettingsBillingCreditsSection

and there’s also other components defined using primitive components H2, Button so I did not list them here and we consider only above two for review.

SettingsBillingSubscriptionInfo

This above shown screenshot is from the Twenty billing, this component SettingsBillingSubscriptionInfo renders this info.

It has the following props:

<SettingsBillingSubscriptionInfo
  currentWorkspace={currentWorkspace}
  currentBillingSubscription={
    currentWorkspace.currentBillingSubscription
  }
/>
Enter fullscreen mode Exit fullscreen mode

And this currentWorkspace is defined as follows:

const currentWorkspace = useAtomStateValue(currentWorkspaceState);
Enter fullscreen mode Exit fullscreen mode

SettingsBillingCreditsSection

SettingsBillingCreditsSection is defined as shown below:

{hasNotCanceledCurrentSubscription &&
  currentWorkspace &&
  currentWorkspace.currentBillingSubscription &&
  isGetMeteredProductsUsageQueryLoaded && (
  <SettingsBillingCreditsSection
    currentBillingSubscription={
      currentWorkspace.currentBillingSubscription
    }
  />
)}
Enter fullscreen mode Exit fullscreen mode

isGetMeteredProductsUsageQueryLoaded is defined as shown below:

const { isGetMeteredProductsUsageQueryLoaded } =
    useGetWorkflowNodeExecutionUsage();
Enter fullscreen mode Exit fullscreen mode

About me:

Hey, my name is Ramu Narasinga. Email: ramu.narasinga@gmail.com

Tired of AI slop?

I spent 3+ years studying OSS codebases and wrote 350+ articles on what makes them production-grade. I built an open source tool that reviews your PR against your existing codebase patterns.

Your codebase. Your patterns. Enforced.

Get started for free —thinkthroo.com

References

  1. twentyhq/twenty

  2. alan2207/bulletproof-react/docs/state-management.md

  3. twenty/packages/twenty-front/src/pages

  4. twenty/packages/twenty-front/src/…/SettingsBilling.tsx

  5. twenty/packages/twenty-front/src/…/SettingsBillingContent.tsx#L21

  6. https://jotai.org/

  7. twenty/blob/main/packages/twenty-front/src/modules/settings/billing/hooks/usePlans.ts#L5

Top comments (0)