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 withReact.FC
orReact.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:
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:
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.