React Projects
Project Setup​
RULE #1: always start a new project with a fresh new installation of Create React App (https://github.com/facebook/create-react-app) with the latest framework and libraries. If the project is similar to a previous one, still do not clone it! In this second scenario, after creating a new project with everything up to date you can copy and paste single functionalities if needed; it would be better to rethink everything. In this way, you can find useless dependencies, dead code, code smells, and pitfalls..
RULE #2: if you plan to start from an old React project, update all dependencies first. Do not start to work with outdated packages.
RULE #3: create-react-app comes with yarn as default package manager, use it!
RULE #4: React doesn't force conventions: everyone can setup a project in a random way. The convention must be defined in a per company way and followed for every project.
RULE #5: before starting a new project, read the official documentation to find out new features and to remember forgotten ones: https://reactjs.org/docs/getting-started.html
Must to have packages​
It's easy to start with few packages and finish the project with lot of dependencies. Despite other frameworks and languages, node packages tend to be less stable during time (that means lot of breaking changes). So the goal is to add only a few libraries and follow these best practices:
- Do not add packages that are not actively maintained or with a few stars
- Do not add unknown packages just to reinvent a little wheel: see what they do and create a library.js inside the lib folder
- Add the minimum number of packages to your project: more dependencies mean more issues in the future if you have to upgrade the project
Below a list of packages that can be always be included:
- react-query to handle communications with remote APIs: https://react-query.tanstack.com/
- react-router-dom to handle navigation: https://reactrouter.com/web/guides/quick-start
- react-hook-form, to easily work with forms: https://react-hook-form.com/
- react-i18next, to add internationalization to your project: https://react.i18next.com/
- moment, to work with dates: https://momentjs.com/
- lodash, as general utility library: https://lodash.com/
- axios, to perform remote calls: https://github.com/axios/axios
- joy as validator: https://github.com/sideway/joi
Why using React Query? Some of the features that React Query provides include:
- Providing hooks useful with function components
- Abstracting the underling library to perfom remote calls (like axios)
- Can be used ofr both REST and GraphQL APIs
- Using window focus pre-fetching mechanism to pre-fetch the data depending on application tab activity.
- We can set the number of request retries for any request, in case of random errors.
- It's easy to perform APIs polling
- Performs pre-fetching so that the application can update stale data in the background.
- Handling complex application caching so that the request operation is optimized.
- Allow to performs dependant queries
- The difference between React-Query and the common data fetching patterns such as useEffect, is that React Query will first return the previously fetched data and then re-fetch it again. If the resource is the same as the first, React Query will keep both the data as a reference without forcing the page to reload.
State Management​
Avoid the use of complicated and unfriendly libraries like Redux, MobX, React Redux Form.
The advice is to delay the use of Redux (and in general a global state manager) until it's really needed by your application.
Consider instead to use React Context https://reactjs.org/docs/context.html or Recoil https://recoiljs.org/ that provide funcionalities easy to understand and ready for the mojority of projects.
Project Structure​
React gives you the ability to choose which project structure best fits your needs: the only advice is to be consistent through all the development process.
The best way to structure projects is to locate CSS, JS, and tests together inside folders grouped by feature or route: the definition of a "feature" is not universal, and it is up to you to choose the granularity.
common/
AvatarComponent.js
AvatarComponent.css
feed/
index.js
FeedComponent.js
FeedComponent.css
FeedsPage.js
FeedsPage.test.js
FeedPage.js
FeedPage.test.js
profile/
index.js
ProfilePage.js
ProfileHeader.js
ProfileHeader.css
api/
index.js
mutations.js
queries.js
Style guide & Linting​
Consider using JavaScript Standard Style: https://github.com/standard/standard That's the simple to setup and very widely used formatter, linter and style checker on the market.
Best Practices​
Follow the AirB&B style guide​
This style guide is mostly based on the standards that are currently prevalent in JavaScript: https://github.com/airbnb/javascript/tree/master/react
Use lazy imports​
As your app grows your bundle will grow too. Code-splitting your app can help you “lazy-load” just the things that are currently needed by the user, which can dramatically improve the performance of your app: https://reactjs.org/docs/code-splitting.html
Don't Define a Function Inside Render:​
Don’t define a function inside render. Try to keep the logic inside render to an absolute minimum
const submitData = async data => {
await mutation.mutateAsync(data)
}
return (
<button onClick={submitData}>
This is a good example
</button>
)
Use Memo​
Memo can significantly improve the performance of your application. It helps you to avoid unnecessary rendering:
import React, {useState} from "react";
const ChildrenComponent = React.memo(({name}) => {
console.log('rendered only once')
return <div>{name}</div>
})
Use Object Destructuring​
Use object destructuring to your advantage. Let’s say you need to show a user’s details.
const { name, email, role } = user;
return (
<>
<div>{name}</div>
<div>{email}</div>
<div>{role}</div>
</>
)
Use Template Literals​
Use template literals to build large strings. Avoid using string concatenation. It’s nice and clean.
const userDetails = `${user.name}'s role is ${user.role}`
return (
<div>{userDetails}</div>
)
Import in Order​
Always try to import things in a certain order. It improves code readability. The rule of thumb is to keep the import order like this:
- Built-in
- External
- Internal
Component Naming​
Always use PascalCase for components and camelCase for instances
import FeedComponent from './FeedComponent';
const feedComponent = <FeedComponent />;
Prop Naming​
Always use camelCase for prop names or PascalCase if the prop value is a React component.
<FeedComponent
userName="hello"
phoneNumber={12345678}
UserComponent={UserComponent}
/>
Use function components where possible​
Functional components are JavaScript (or ES6) functions that return React elements. They’re a bit easier to understand because there isn't as much going on as there would be in a class component. They can also be written as a simple JS functions or as an arrow function using ES6 syntax, and their props are passed in as arguments (if any).
Here's some pros in using functional components:
- Functional Components are basic JavaScript functions
- They use hooks!
- Easier to test: You don’t have to worry about hidden state and there aren’t as many side effects when it comes to functional components, so for every input, the functions will have exactly one output.
- Easier to read/write: The syntax is less complex than that of class components, and it’s easier to read due to knowing how much you can’t do with functional components already. The use of prop destructuring makes it really beneficial to see what’s going on and what’s coming out of the component.