• Blog
  • Documentation
  • Courses
  • Changelog
  • AI Starters
  • UI Kit
  • FAQ
  • Supamode
    New
  • Pricing

Launch your next SaaS in record time with Makerkit, a React SaaS Boilerplate for Next.js and Supabase.

Makerkit is a product of Makerkit Pte Ltd (registered in the Republic of Singapore)Company Registration No: 202407149CFor support or inquiries, please contact us

About
  • FAQ
  • Contact
  • Verify your Discord
  • Consultation
  • Open Source
  • Become an Affiliate
Product
  • Documentation
  • Blog
  • Changelog
  • UI Blocks
  • Figma UI Kit
  • AI SaaS Starters
License
  • Activate License
  • Upgrade License
  • Invite Member
Legal
  • Terms of License
  • Auth Overview
  • Global Configuration
    • Setting up your Firebase Project
    • Setting up Firebase Functions
  • Writing data to Firestore
  • Commands
  • Introduction
  • Production Checklist
  • Introduction
  • Overview
  • Stripe Configuration
  • Running Tests
  • Introduction
  • Setting up Firebase Auth
  • Fetching data from Firestore
  • Technical Details
  • Extending Organizations
  • Stripe Webhooks
  • CI Tests
  • Initial Setup
  • React Hooks
  • Auth Flow
  • API requests
  • Code Style
  • Clone the repository
  • Security Rules
  • User Permissions
  • Limitations
  • Project Structure
  • Third-Party Providers
  • Reading data from Storage
  • Running the application
  • Subscription Permissions
  • One-Time Payments
  • Running the App
  • Email Link Authentication
  • Uploading data to Storage
  • Security Rules
  • Migrate to Lemon Squeezy
  • Project Configuration
  • Multi-Factor Authentication
  • Writing your own Fetch
  • Translations and Locales
  • Coding Conventions
  • Environment Variables
  • Architecture and Folder Structure
    • Structure your Application
    • Data Model
  • Requiring Email verification
  • Sending Emails
  • Tailwind CSS and Styling
  • Validating API payload with Zod
  • Authentication
  • Onboarding Flow
  • Logging
  • Development: adding custom features
  • Prevent abuse with AppCheck
  • Enable CORS
  • Encrypting Secrets
  • User Roles
  • Firestore: Data Fetching
  • Custom React Hooks
  • Custom React Hooks
  • Firestore: Data Writing
  • Troubleshooting
  • Forms
  • Application Pages
  • API Routes
  • API Routes Validation
  • Translations
  • Adding pages to the Marketing Site
  • Deploying to Production
  • Updating to the latest version
This kit is no longer maintained.

SaaS template Coding Conventions

An explanation of the coding conventions used in the boilerplate

React.FC vs React.FCC

Since React 18, React.FC no longer implies that components can accept a children prop. The alternative to that is using the interface React.FC<React.PropsWithChildren<{}>>, which is a bit long.

React.FCC is a shorthand that includes children as a possible property that works similarly to how it used to work. When a component needs children, React.FCC is preferred since it's faster to type.

Exporting functions vs constants

We use both conventions in the boilerplate, i.e., exporting functions as components and constants.

My general rule is the following:

  • if it's the exported component, use const typed with React.FC or React.FCC
  • if it's not exported, use function since my personal preference is to define functions below the exported component

NB: sometimes, that may not be the case, and that's not necessarily intentional. The two constructs are essentially the same in most cases.

Why is useCallback used in most components?

Most functions defined within a render function use useCallback. In my experience, this is the better default to avoid re-renders that I can't immediately explain.

Whether you want to adhere to this convention is totally up to you; just be aware of the potential issues.

Interfaces, Types, and Inline

I've gone through phases, so you may find some types defined as type and others as interface. I've since realized that I prefer interface, but you will find some instance that uses type.

Inline types are typically only defined when the type isn't reused anywhere. For example, when defining a function that accepts parameters as objects.

Function parameters

I adhere to the principle that if a function accepts multiple parameters of the same type, then use an object. Unfortunately, Typescript can't save us if the types match.

Consider the example below:

tsx
function makeDiv(width: number, height: number) {}
const height = 10;
const width = 40;
// correct according to TS, not in practice!
const div = makeDiv(height, width);

Now we rewrite it using an object:

tsx
function makeDiv(params: { width: number, height: number}) {}
const height = 10;
const width = 40;
// Okay, now it looks better!
const div = makeDiv({ height, width });

Custom React Hooks

The boilerplate uses Custom React Hooks when:

  • fetching/writing using an API function
  • fetching/writing using Firestore
  • fetching/writing using Storage

It makes the code more understandable and reusable.

On this page
  1. React.FC vs React.FCC
    1. Exporting functions vs constants
      1. Why is useCallback used in most components?
        1. Interfaces, Types, and Inline
          1. Function parameters
            1. Custom React Hooks