DEV Community

Cover image for reducks, a boilerplate
jan paul
jan paul

Posted on • Updated on

reducks, a boilerplate

img by Jase Ess

Hello dear dev.to,

Iam working for instant-data. a small company that provides solutions in the environment of a larger advertising agency. mostly internal toolings.

After playing round a little with the create-react-app, i wanted to share my latest boilerplate with you and ask for your opinions, or improvements. You can visit me here on github.
In this i follow the ducks pattern, in which you try to keep all your redux and store reducer stuff in one single file, but for sakes of DRY, i will present you the README.MD. I appreciate any feedback ;-)

It is created via the CLI-Tool

create-react-app <your-appname> --scripts-version=react-scripts-ts

and customized to my needs, by running

npm eject

Prequisites

Installed node and npm Version 8 or higher.

Available Scripts

In the project directory, you can run:

npm start

Open http://localhost:3000 to view it in the browser.

npm run build

Builds the app for production to the build folder.

npm run seed Authentication seed

To make the boilerplate work from scratch, and to simulate the flow of Auth, we put a JSON-Server.
You should remove the complete seed folder, or better add it to your .gitignore, when you implement your own workflow. To make use of it simply npm run seed. You will get served at json-server --port 4000 --watch -- seed/db.json.

Folder Structure

After creation, your project should look like this:

my-app/
  README.md
  node_modules/
  package.json
  public/
    index.html
    favicon.ico
  seed/
    /* a helper fake backend for firsttimers */  
  src/
    index.tsx
    components/
      App.tsx
    containers/
      /* your connected containers here */
    ducks/
      /* your ducks here */
    services/
      /* put all your global helpers inside here */
    store/
      history.ts
      index.ts
      localStorage.ts
  types/
    /*your types go here */  

Debugging and DevTools

I strongly suggest you to install and use theses BrowserExtensions.

Material-UI and Decorators

The experimental feature for Decorators is activated in the tsconfig.json. By this it is possible to use the withStyle decorator in combination with compose of the recompose package.
Example usage is:

import { compose } from 'recompose';
import { withStyles } from '@material-ui/core/styles';

@(compose(withStyles(styles)) as any)
class Example extends React.Component<IExampleProps, IExampleState> {...}

To make use of themes in material-ui we need to wrap the content of App inside a

<MuiThemeProvider theme={createMuiTheme()}>
  //any content here
</MuiThemeProvider>

read more about Material UI Themes

Environment

There is the possibility to provide ENV variables. use the .env file for this.
Please note, they need to follow the naming convention of REACT_APP_ EXAMPLE=FOOBAR.
Inside the project one can consume them by proccess.env.REACT_APP_EXAMPLE.
At a new start its set to the seedings path, so one might want to change it there.

HTTP Requests

Please use axios for your requests. It supports Promises and also async/await.
https://github.com/axios/axios
Also make sure the allow crossorigin-access on your server.

Ducks

We follow the 'Ducks'-Pattern to structure our application. Get insights on this specc here
https://github.com/erikras/ducks-modular-redux
The pattern is to have all these inside one duck:

  • action enum
  • action types
  • action creators
  • reducer functions
  • mainreducer
  • thunk
  • initialStore

Message Component

There is a rudimental example prepared in this boilerplate, that shows usage and consumption of a high level message or notification-component. Import the NofictationDuck inside the Ducks that you want the NotificationStore to be catched.

import NotificationDuck from '~/src/ducks/notification';

your.action()
  .then(() => /* success */)
  .catch((err) => {
      dispatch(NotificationDuck.throwNotificationWithError({text: 'your text', title: 'your title'}))
  })

But you can also connect them directly to components. Please keep in mind to reset the NotificationStore, with the RESET_NOTIFICATION_STORE action!

Store

Use the folder src/store to configure the store of redux according to your needs. There is also the possibilty to subscribe parts of the store to your localStorage. To do so check the index.ts and have a brief look at the store subscribe pattern.

store.subscribe(throttle(() => {
  const storage = store.getState() as RootState;
  const AuthStore = storage.AuthStore;

  saveState({
    AuthStore
  } as RootState);
}, 300));

Please make use of the throttle lodash-helper. JSON.parse()/JSON.stringyfy are expensive in Javascript.

Services

Anything you want to consume repetitive belongs to the services. Another word could be globalHelpers.

  • apicontroller -> an axois instance the can be configured. import it into your ducks to make http-verbs.
  • authenticationService -> can be used in conjunction with apicontroller inside of ducks to verify auth-Status

inside your duck - an example usage in thunk

import axios from '../../services/apicontroller';

public static getAuth() {
    return function (dispatch: any, getState:() => RootState): Promise<void> {
      dispatch(AuthDuck.getAuthAction());

      //return the axois object with header, pass the state by `getState()` to auth and GET the route with `get('/yourRoute')`

      return axios(getState()).get('/Authentication')
        .then((res) => {
          dispatch(AuthDuck.getAuthSuccessAction(res.data));
         })
        .catch((err: Error) => {
          /**
        });
    };
  }

There is also a whole react-router v4 part, i will explain at 50 :heart: :-)

Discussion (0)