Appearance
Frontend Style Guide
This style guide provides best practices and style conventions for writing React Native code using TypeScript.
Table of Contents
- General Guidelines
- Naming Conventions
- Components and Screens
- File and Folder Structures
- Static Typing
- Styling
- Documentation Expectations
- Ending Notes
General Guidelines
- Keep your code DRY (Don't Repeat Yourself).
- Keep it modular. Each component or function should only do one or two things!
- Write clear and concise code. Favor readability over cleverness.
- Keep it consistent with the coding style defined below.
- Use comments to clarify code, but do not comment obvious code.
Naming Conventions
2.1 General
- Camel Case: Use camelCase for variable and function names. This convention involves starting each word except the first with a capital letter (e.g.,
myVariable
,calculateTotal()
). - Pascal Case for Components: Use PascalCase for React components. This convention involves capitalizing the first letter of each word, including the first one (e.g.,
MyComponent
,HeaderSection
,HomeScreen
). - Lowercase File Names: Use all lowercase file names when defining/creating a file that will display one of the screen components (i.e
ChatroomScreen
,WelcomeScreen
) inside the app router folders/stacks.
2.2 Variable Definitions
Descriptive Variable Names: Choose descriptive names for variables that convey their purpose. Avoid overly abbreviated or unclear names. For example:
typescript// Good const userName: string = 'JohnDoe'; // Avoid const un: string = 'JD';
// Good const userName: string = 'JohnDoe'; // Avoid const un: string = 'JD';
If you are worried about the variable name being too long, favor long variable's with clarity over short variables that hinder clarity!
Avoid Similar Names: Choose variable names which are not super similar with any other function or variable to reduce confusion:
typescript// Good const message: string = 'This is a message!'; const messageList: MessageType[] = [] // This is a list of messages! // Bad const message: string = 'This is a message!'; const messages: MessageType[] = [] // This is a list of messages, but confusing!
// Good const message: string = 'This is a message!'; const messageList: MessageType[] = [] // This is a list of messages! // Bad const message: string = 'This is a message!'; const messages: MessageType[] = [] // This is a list of messages, but confusing!
Boolean Prefixes: Prefix boolean variable names with "is" or "has" for clarity. This improves readability and signals the variable's boolean nature. For example:
typescriptconst isActive: boolean = true; const hasError: boolean = false;
const isActive: boolean = true; const hasError: boolean = false;
2.3 TypeScript Interface Names
Interfaces are important to utilize and understand as you will be using them a lot for declaring component props
and making typescript types
.
Descriptive Interfaces: Use descriptive names for TypeScript interfaces. Clearly define the structure of objects passed as props or state.
typescriptinterface UserProfile { username: string; email: string; age?: number; // '?' indicates optional property }
interface UserProfile { username: string; email: string; age?: number; // '?' indicates optional property }
Singular Nouns for Interfaces: Use singular nouns for interfaces representing a single entity.
typescriptinterface Car { brand: string; model: string; year: number; }
interface Car { brand: string; model: string; year: number; }
Components and Screens
Keep component names short and straight to the point. The components with the Screen
suffix are where the different pages are put together.
Use Arrow Function Components: Prefer to use the arrow function over the traditional function for making componenets
typescript// Good const MyComponent : React.FC = () => { }; // Bad function MyComponent() { };
// Good const MyComponent : React.FC = () => { }; // Bad function MyComponent() { };
Modulate Your Program: Make a component for all the small controls/visuals instead of hard-coding one into your
Screen
componenttypescript// Good import { LoginButton } from '###' const HomeScreen : React.FC = () { <LoginButton /> } // Bad const Homescreen : React.FC = () => { <Button> // This button needs all its styling and set-up in this file! </Button> }
// Good import { LoginButton } from '###' const HomeScreen : React.FC = () { <LoginButton /> } // Bad const Homescreen : React.FC = () => { <Button> // This button needs all its styling and set-up in this file! </Button> }
Compile in the Screens: Building each component and then linking them all up within themselves then importing into
Screen
files overcomplicates things! Assemble your components within the actualScreen
files/components themselves!
File and Folder Structures
A clean and simple folder structure is a key aspect of a less painful developing experience. Instead of importing components from all over the repository, we have a set structure to where and what each folder should be and what it should contain.
Simple Directory Tree (Current)
Tree
├── assets
├── src
│ ├── app
│ ├── components
│ │ ├── Auth
│ │ ├── Chat
│ │ ├── Common
| | ├── Home
│ │ ├── Settings
│ │ └── _deprecated
│ ├── services
│ ├── sockets
│ └── utils
└── App.tsx // Deprecated
├── assets
├── src
│ ├── app
│ ├── components
│ │ ├── Auth
│ │ ├── Chat
│ │ ├── Common
| | ├── Home
│ │ ├── Settings
│ │ └── _deprecated
│ ├── services
│ ├── sockets
│ └── utils
└── App.tsx // Deprecated
- /src: our main source folder that hosts our current working codebase
- /src/app: contains the main app router and all the screens that are linked to it
- /src/components: contains all the components that are used in the app
- /src/components/Auth: contains all the components that are used in the authentication process
- /src/components/Chat: contains all the components that are used in the chat process
- /src/components/Common: contains all the components that are used in multiple processes
- /src/components/Home: contains all the components that are used in the home process
- /src/components/Settings: contains all the components that are used in the settings process
- /src/components/_deprecated: contains all the components that are no longer used in the app
- /src/services: contains all the services that are used in the app
- /src/sockets: contains all the sockets that are used in the app
- /src/utils: contains all the utilities that are used in the app
- /assets: contains all the assets that are used in the app
A Simple File Structure
Below is a simple file structure for a component. This is a good starting point for any Screen
or standalone component you make. You can add more files as needed, but this is a good starting point.
typescript
import {} from 'react-native'; // And all other imports
// Any logic should be right above the component
const MyComponent : React.FC = () => {
return (
<View>
<Text>My Component</Text>
</View>
);
};
styles = StyleSheet.create({
// Styles
});
export default MyComponent; // Good for standalone components/Screens
import {} from 'react-native'; // And all other imports
// Any logic should be right above the component
const MyComponent : React.FC = () => {
return (
<View>
<Text>My Component</Text>
</View>
);
};
styles = StyleSheet.create({
// Styles
});
export default MyComponent; // Good for standalone components/Screens
Here is a simple file structure for a multi-use component. This is a good starting point for any Common
component you make.
typescript
import {} from 'react-native'; // And all other imports
export const SignInButton : React.FC = () => { // Export inline
return (
<Button>
// Button Stuff
</Button>
);
};
// Button logic should be right above the component
export const LoginButton : React.FC = () => {
return (
<Button>
// Other Button Stuff
</Button>
);
};
import {} from 'react-native'; // And all other imports
export const SignInButton : React.FC = () => { // Export inline
return (
<Button>
// Button Stuff
</Button>
);
};
// Button logic should be right above the component
export const LoginButton : React.FC = () => {
return (
<Button>
// Other Button Stuff
</Button>
);
};
Static Typing
This may be a little weird to begin doing, especially if you are coming from a dynamically typed language like JavaScript. However, it is important to understand the benefits of static typing and how it can help you write less error-prone code.
Declaring Types
You may have noticed in the above examples some code that looks slightly different than vanilla Javascript:
typescript
const MyComponent : React.FC = () => {
};
// or...
const userName: string = 'JohnDoe';
const MyComponent : React.FC = () => {
};
// or...
const userName: string = 'JohnDoe';
Declare your components and variables with their types! You can do this by adding a :
and the type after the variable/component name. If you are unsure of what type your variable or component is, you search it up in the TypeScript Docs or use the any
type (which is not recommended).
React's component class has a type React.FC
which stands for React Functional Component. This is the type you should use for all your components.
Defining Props
Also when you pass in props
to your component, you should declare the type of the props
object. For example:
typescript
interface MyComponentProps {
name: string;
age: number;
}
const MyComponent : React.FC<MyComponentProps> = ({ name, age }) => {
return (
<View>
<Text>{name}</Text>
<Text>{age}</Text>
</View>
);
};
interface MyComponentProps {
name: string;
age: number;
}
const MyComponent : React.FC<MyComponentProps> = ({ name, age }) => {
return (
<View>
<Text>{name}</Text>
<Text>{age}</Text>
</View>
);
};
Defining State Types
When you define state in your component, you should declare the type of the state object. For example:
typescript
interface MyComponentState {
name: string;
age: number;
}
const MyComponent : React.FC = () => {
const [state, setState] = useState<MyComponentState>({
name: 'John Doe',
age: 20
});
return (
<View>
<Text>{state.name}</Text>
<Text>{state.age}</Text>
</View>
);
};
interface MyComponentState {
name: string;
age: number;
}
const MyComponent : React.FC = () => {
const [state, setState] = useState<MyComponentState>({
name: 'John Doe',
age: 20
});
return (
<View>
<Text>{state.name}</Text>
<Text>{state.age}</Text>
</View>
);
};
Styling
Currently we are using plain CSS for styling our components. We are using the React Native StyleSheet to style our components. More libraries may be added in the future to make styling easier.
Naming Conventions
Descriptive Class Names: Use descriptive names for CSS classes. Clearly define the purpose of the class. Avoid overly abbreviated or unclear names. For example:
typescript// Good const styles = StyleSheet.create({ mainContainer: { // ... }, }); // Bad const styles = StyleSheet.create({ mainC: { // ... }, });
// Good const styles = StyleSheet.create({ mainContainer: { // ... }, }); // Bad const styles = StyleSheet.create({ mainC: { // ... }, });
If you are worried about the class name being too long, favor long class names with clarity over short class names that hinder clarity! Use the
camelCase
naming convention for class names.Use
Dimensions
for Sizing: Use theDimensions
API to get the width and height of the screen. This ensures that your components will be sized correctly on all devices. For example:typescriptimport { Dimensions } from 'react-native'; const { width, height } = Dimensions.get('window'); const styles = StyleSheet.create({ mainContainer: { width: width * 0.8, // 80% of screen width height: height * 0.5, // 50% of screen height }, });
import { Dimensions } from 'react-native'; const { width, height } = Dimensions.get('window'); const styles = StyleSheet.create({ mainContainer: { width: width * 0.8, // 80% of screen width height: height * 0.5, // 50% of screen height }, });
This is for increased responsiveness and scalability of the app. Also opt for using percentages and flexbox over hard-coded values.
Documentation Expectations
Documentation is one of the most important aspects of a project. As an Open Source project, we want to make sure that our code is well documented and easy to understand. This will help us onboard new developers and make it easier for everyone to understand the codebase.
- Documenting New Code: When you write new code, make sure to document it. This can be done by either adding comments to your code or by appending or adding new content to this website.
- Add Documention to the Correct Section: If you are adding documentation to this website, make sure to add it to the correct section. For example, new
Socket.io
documentation should be added to the correspondingSocket
section. etc etc. - Documenting Existing Code: If you are working on existing code, document your changes and edit the current docs.
- Keep It Short: Make sure you do not over document your code! Just enough so that people can understand.
Ending Notes
There are a lot of ways to program and a lot of ways to write code. This is just a simple guide to help you get started with the project.
If you undergo a code review and your code is denied/flagged, do not take it personally! We are all here to learn and grow as developers. If you have any questions, feel free to ask in the Discord server!
Happy Coding! 😄