.
├── __tests__/ # Integration tests
├── docs/ # Documents (always out-of-date)
│ ├── architecture.md
│ └── CONTRIBUTING.md
├── src/
│ ├── actions/ # Redux actions
│ ├── components/ # React components
│ │ ├── List/ # Display Hero list
│ │ ├── Profile/ # Display a hero's profile
│ │ └── Main.js # Entry wrapper
│ ├── reducers/ # Redux reducers
│ ├── store/ # Redux store and middlewares
│ ├── App.js # Component handling redux store
│ ├── index.html
│ └── index.js
├── dist.sh* # Simple script to push dist/* to gh-pages
├── LICENSE
├── package.json
├── README.md
├── webpack.config.js
└── yarn.lock
The ideal component style in this project is dumb components (a.k.a presentational components). All computations such as state selections and asynchronous actions should all keep outside a React component's life cycle as possible. The only exception is container conponents.
The components files are arranged as below:
- Put under
src/compoents
directory. - The first letter of files or directories of compoents must be capitalized.
- All container components must be put in a directory named after itself. Under the directory, create two files:
- An
index.js
file thats serve as a container compoents. - A
[dirname].js
file named after the directory serve as presentational components.
- An
In this project, we put related container and presentational components as near as possible, instead of separating thems into two places.
There is no magic in reducers. We try our best to follow major design patterns and what Redux documentation says. All async action goes to Epics. Modules under src/actions/
directory are action constants action creators. The purpose of these modules is just for readability and traceability.
The only action creators outside src/actions/
are React Router history creators (e.g. push
, replace
). We may move them into the directory someday.
Epics are asynchronous action handlers defined by Redux-Observable. The major difference between Redux-Thunk and it is that Redux-Observable not only gives you the raw power to use Redux Store, but also enhances the action handling process more happier with the core concept of RxJS: all data are observable streams.
In this project, all epics goes into the same module file of related reducers. The reason is that it would be closer to other epics to combine with. And then combined epic can easily inject into Redux as a middleware. Though the role of epics may be more similiar to action creators, and functions epics calling are almost action creators-related. As the project grows, we need to figure out a way to manage epics.
There is no magic in reducers. We try our best to follow major design patterns and what Redux documentation says. Again, no magic in reducers.
The project use reselect
to select and memorize state of interest (SOI) of a component. The selector pattern can separate state from component rendering process, and make UI state more testable.
All reducer-specific selectors must be put in its dependant reducers. For example, getButtonEnabled
selector only concern about availablePoints
and profile
state, so its can derive from state.profile
without touching any other top-level reducers.
The directory to settle cross-reducer selectors is undefined. We should figure it out someday.
This project adopts Jest as the main testing framework. All test files are arranged with following rules:
- Naming: All test modules are named after the target module with
*.test.*
suffix. For example, test module ofselectors.js
must be named asselectors.test.js
. Test module ofProductList.tsx
must be named asProductList.test.tsx
. - Unit tests: Put under the same directory of target module.
- Integration tests: Put under top level
__tests__/
directory.
UI framework
The project apply styling with Blueprint framework, a React-based framework targeting on data-dense website. It is only an opinionated decision.
The project uses style-loader and css-loader along with Webpack to bundle all CSS file into index.html
at build time. We may need to split CSS from other scripts via extract-text-webpack-plugin in the future.
Custom CSS rules
Besides UI framework we choose, all the other custom CSS styling file must be put under the same directory of the component it decorates, and the filename should be style.css
. For example, src/components/List/List.js
React component gets a CSS styling in src/components/List/style.css
. This CSS file would decorate all components under the same level unless there is another subdirectory containing another component.