How to treat component as TypeSafe in Redux + Atomic Design
Tags: javascript, typescript, react, redux
Published: 2018-11-05 04:35:16

---
title: How to treat component as TypeSafe in Redux + Atomic Design
published: true
description: I wrote a way to handle TypeSafe components in Redux and Atomic Design which I thought was written in Japanese Qiita, so I rewrite it to English.
tags: JavaScript,TypeScript,React,redux
---

>It rewritten what I made an article on Nihon Qiita technology sharing service to English.
>The article of Japan is as follows.
>
>[俺の考えたRedux + Atomic DesignでTypeSafeにコンポーネントを扱う方法](https://qiita.com/konojunya/items/5042da2257bb1a85fcac)



It is poem. Let's take notice of browsing :)

First of all apologize because you may think you do not understand Atomic Design in the first place.
Just as a common recognition, I also write it in the document, so I will use this method to operate.

# Directory structure

```
- src/
    - actions/
        - hoge.ts
    - api/
        - client.ts
    - components/
    - model/
        - type.ts
    - store/
        - index.ts
        - reducer-type.ts
        - sagas/
        - reducers/
```

`ActionCreator` is described in` actions`.
The API surroundings (communication using axios) are summarized in `client.ts`.

The `components` subordinate is modeled on Atomic Design.

`model/type.ts` is managed by separating them with namespace `Payload` `Response` `Domain`.
For example, if you use API to login with email and password `Payload.Signin`

like

```ts
interface Signin {
  email: string;
  password: string;
}
```

This is a type to be used as Payload of `Action` later.

The response of that API is summarized in `Response.Signin`.

example

```ts
interface Signin {
  name: string;
  icon: string;
  token: string;
}
```

`store` in addition to `index.ts` doing `combineReducer` etc, there is `reducers` which defines Reducer, `sagas` which writes saga, and so on.

It is `reducer-type.ts` that helps the shape that I created in this project.

# What is contents of reducer-type.ts

`reducer-type.ts` has the following contents.

```ts
export interface ReduxAPIError {
  statusCode: string;
  message?: string;
}

interface ReduxAPIStruct<T> {
  isLoading: boolean;
  status: "success" | "failure";
  data: T;
  error: ReduxAPIError;
}

export const defaultSet = <T>(defaultValue?): ReduxAPIStruct<T> => ({
  isLoading: false,
  status: null,
  data: defaultValue || null,
  error: errorDefault()
});

export const errorDefault = (): ReduxAPIError => ({
  statusCode: null,
  message: ""
});

export default ReduxAPIStruct;
```

Inside the application I read this useful tool as `ReduxAPIStruct`.

What is important is the interface below.

```ts
interface ReduxAPIStruct<T> {
  isLoading: boolean;
  status: "success" | "failure";
  data: T;
  error: ReduxAPIError;
}
```

Each describes the motion when communicating with the application.

`isLoading` is managed by boolean and deals with whether or not it is loading.
`status` is created to facilitate fallback to the error component later.
`data` is the data body when actually obtained from the API. Here is defined as generic with `T`. When using this type later, pass the `Response` type of `model/type.ts` just as it is.
`error` has a type called `ReduxAPIError`.

```ts
export interface ReduxAPIError {
  statusCode: string;
  message?: string;
}
```

`ReduxAPIError` has `statusCode` and `message`.
`statusCode` sets the statusCode of the response when accessing that API.
Message has a type to insert it in the response body from the server and later in saga.

# A world with ReduxAPIStruct

First of all, as an important point of what imitated Atomic Design, we separated the clear responsibilities of `pages` and `template`.
For example, connect redux only to components of `paegs` class.

We define `pages` as **a single page which has data and is linked to the URL** .
On the other hand, `template` was created as **a UI based on data** .

By separating this clear obligation, the `pages` component looks like this.

For example, I would like to create an article list page that receives the following data.

```json
{
  "items": [
    {
      "title": "タイトル1",
      "body": "本文1"
    },
    {
      "title": "タイトル2",
      "body": "本文2"
    },
    {
      "title": "タイトル3",
      "body": "本文3"
    }
  ]
}
```

Suppose that the endpoint of this API is `[GET] /items` and the axios API client is an implementation as follows.

```ts
import axios from "axios";

class Client {
  public getItems() {
    return axios.get("/items");
  }
}
```

The client implements it to return `Promise` .

The saga code will end, but let's say the result is in the key `items` of `article reducer` .

```tsx
import * as React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router";
import { requestGetItems } from "~/actions/article";
import ErrorHandler from "~/ErrorHandler";

// templates
import ItemsPageTemplate from "~/components/templates/ItemsPage";
import LoadingTemplate from "~/components/templates/Loading";

// type
import { Response } from "~/model/type";
import ReduxAPIStruct from "~/store/reducer-type";

interface Props {
  items: ReduxAPIStruct<Response.Article.Items>;
}

class ItemPage extends React.Component {
  public render() {
    const { items } = this.props;
    if(items.status === "failure") {
      return <ErrorHandler errorStatus={items.error.statusCode}/>;
    }

    return items.isLoading ? <LoadingTemplate /> : <ItemsPageTemplate items={items.data} />;
  }
}

export default wituRouter(connect(
  state => ({ items: state.articleReducer.items })
)(ItemPage) as any);
```

If data is being acquired with this, `LoadingTemplate` will fail and fetch of data will fail.
If it fails to `ErrorHandler` it succeeds and `ItemsPage` will be mounted.

You can manage these three states regardless of which page you write or not thinking about anything.

Thanks to ReduxAPIStruct you can easily understand whether that data is in fetch or not, and failing fetch can also be understood by looking at `status`.

When saga is written by cutting this state management to another state, it is possible to manage the state without thinking about the component.

# Afterword

I translate my English using Google Translate. If there is a mistake as a description of English, please point out with comments :(

Twitter: [@konojunya](https://twitter.com/konojunya)
GitHub: [konojunya](https://github.com/konojunya)