The reference app could be found here.
- Place the front-end code in a separate repo.
- Create a boilerplate with
create-react-app. - Keep
.envin the root of the front-end repo, not insrc/API/. - Use boilerplate generator like one from https://github.com/react-boilerplate/react-boilerplate.
$ npm run generate container Foo
will create a bunch of files and directories that otherwise you would be creating manually (all with contents!):components/Foo/components/Foo/index.jscomponents/Foo/Foo.jscomponents/Foo/Foo.test.jscomponents/Foo/Foo.csscontainers/FooContainer/containers/FooContainer/index.jscontainers/FooContainer/FooContainer.js
- Define
mainproperty inpackage.json.
Justification: see the NPM docs.
- Put each React component in a module with an interface specified in its
index.js. - Make
components/a module withindex.jswith an entry for each exported component:
export { default as Component } from './Component' - Make
containers/a module withindex.jswith the same entry for each exported component. - Eliminate
src/vendor/. Keep vendor assets inpublic/vendor(only if they are absolutely needed). - Refactor imports according to proposals above.
becomesimport BlogItem from '@src/Components/BlogItem/BlogItem' import Button from '@src/Components/Button/Button'
import { BlogItem, Button } from '@src/components' - Extract container component from
containers/Foo/index.jsintocontainers/Foo/FooContainer.js.
Justification:connect()returns a container component. Each importable component should reside in a separate module. - Move presentational components from
containers/tocomponents/.
containers/BlogItems/BlogItems.jsx->components/BlogItems/BlogItems.jsx.
Justification:/* In containers/BlogItemsContainer/BlogItemsContainer.js */ import { BlogItems } from '@src/components' ...components/should contain all presentational components, not only shared ones. - Eliminate
Routesmodule; move the components it contains tocomponents/. Justification: the components it contains are just presentational components renderingSwitch'es andRoute's.
- Move
Apptocomponents. Justification: it's just a presentational component. As all presentational components, it should reside incomponents/. - Eliminate
Routes/Groups/component; move routes up toApp.
Justification: we use React Router v4. It follows and proclaims the dynamic routing philosophy. We should not try to emulate the static routing approach with it. Also, we should not be afraid of nested routes as they are means of declarative routing (remember the React Router slogan: "Declarative routing for React"). You can see an example of applying this approach in React Router 4: A Practical Introduction
- Introduce
Apisingleton composed with domain-specific mixins instead of the existing bunch of functions.
Justification: we should follow rules of object-oriented design. It will allow us to deduplicate the code, test and maintain it with ease. Example implementation TBD.
- Rename each module that does not export React component or constructor with camelCase.
Justification: in the React world, PascalCase is reserved for constructors and components. - Rename
.jsxfiles to.js. - Add
Containerpostfix to container components' names.
Justification: this way, we will be able to distinguish between presentational and container components right in JSX, without need to scroll up to imports. This approach is recommended by Redux maintainers and is used in example app https://codesandbox.io/s/github/reactjs/redux/tree/master/examples/shopping-cart - Rename
BlogItemstoBlogItemList.
Justification: in the React world,Listis the standard postfix for a list of items. - Rename
app.jstoindex.js.
Justification: it's needed to definepackage.main. - Rename
index_reset.csstoindex.css.
- Reduce Redux-related boilerplate using helper libraries
flux-standard-action,redux-actions,redux-thunk-actions. - Do not define action types separately -- only in
createAction(). Do not dispatch bare actions -- call action creators.