It’s always easier to maintain your project if you give it a nice structure

I guess the title of this post is also the most asked question of any new React developer. There is no easy answer to this question because each project will have a different technology stack and requirements. Even Dan Abramov posted this tweet:

I have taken a screenshot of the website in the Tweet:

While this is a correct advice, it doesn’t work well for new React developers. If you are learning React by yourself and you don’t have real experience with a production-ready React project. It would take a long time before you figure a good structure that fit for your project and coding style. This is the reason why I want to share my opinion in this post 🙂

Project context

Before sharing my project structure, let’s me give you a little context. This structure will work for small to medium size project. By this size project, it means this project has less than 10 pages and less than 150 components. This project also:

  • Manage application state by Redux
  • Follow container and component pattern
  • Fetch and post data to the backend via Rest API
  • It uses SCSS and CSS Module for component styling.

So this is a typical React project.

Structure

There are 6 important folders in the screenshot above. They are assets, components, containers, reducers, services. I will explain the usage of each folder shortly.

Explanation

assets

This folder holds static assets for your app. They could be fonts, icon, SVG or JPEG images or any JSON file, etc. If you have too many file types, you probably want to create some subfolders to hold them.

components

This folder holds all of the components that are responsible for look and feel of your app. These components don’t fetch data by themselves but receive data and callback via props. They also don’t connect to Redux, that is the job of the containers. You probably hear about the container and component patter. Here is the famous explanation about this pattern.

If your project has a lot of pages, you can create some subfolders inside components folder. For each component, you can create a folder to store the component. For example, if you have a SearchBox component, you will create SearchBox folder. Inside of SearchBox folder, we will create 3 files: index.js, SearchBox.js and SearchBox.scss.

index.js will look like this:

export { default } from './SearchBox';

This default export statement allows you import SearchBox easier, so you don’t have to repeat “SearchBox” again in the import path.

// Ngắn gọn
import Searchbox from '../components/Employee/Searchbox';

// Dài hơn
import Searchbox from '../components/Employee/Searchbox/SearchBox';

SearchBox.js contains the implementation for SearchBox component and SearchBox.scss contains the styling for SearchBox component.

containers

This folder contains components that are connected to Redux. These components are called container. Here is an example of a container:

import { connect } from 'react-redux';
import { toggleSearchKeyword } from '../reducers/search';
import SearchBox from '../components/Header/SearchBox';

const mapStateToProps = state => ({
  keyword: state.search.keyword,
});

const mapDispatchToProps = {
  search: toggleSearchKeyword,
};

export default connect(mapStateToProps, mapDispatchToProps)(SearchBox);

reducers

You may wonder why we don’t have the redux related folders like actions, constants or selectors like any regular Redux project. In my opinion, these folders increase the complexity of our projects and when you want to change a simple feature, you have to edit many files. I found that ducks pattern is particularly helpful to organize the Redux files.

How to implement ducks pattern? Let’s take this example, you have search employee feature in your app. Instead of creating many files like: actions/employeeSearch.js, constants/employeeSearch.js and reducers/employeeSearch.js..

We only create a single file: reducers/employeeSearch.js. In this file, we include all of the action creators, constants, selectors and reducer for search employee feature.

Example:

const SET_SEARCH_EMPLOYEE_KEYWORD = 'SET_SEARCH_EMPLOYEE_KEYWORD';

export const setSearchEmployeeKeyword = keyword => ({
  type: SET_SEARCH_EMPLOYEE_KEYWORD,
  payload: keyword,
});

export default function reducers(state = '', action) {
  switch (action.type) {
    case SET_SEARCH_EMPLOYEE_KEYWORD:
      return action.payload;
    default:
      return state;
  }
}

This pattern works well in most of my project.

Notice that we don’t have any subfolder inside of reducers because we want to keep our Redux state at flat as possible. Usually, I don’t have too much data inside Redux state and I only store the application-wide data in Redux state.

services

This folder contains the API service files which helps your React app connects to the backend.

Summary

I hope this post could give you an idea on how to organize your project better. Please don’t stick to this structure, you are free to move your file until you feel it fits better for your project. Feedbacks are welcome 🙂