3
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

[React.js]TypeScriptでRedux-zeroを使ってみる

Reducerが面倒なので、軽量なreduxのライブラリ「redux-zero」を使ってみようと思います。

1.ベースを作る

TypeScriptが好きなので、下記記事をもとにReact + Redux + TypeScriptのベースを作ります。
https://qiita.com/uryyyyyyy/items/3ad88cf9ca9393335f8c

2.redux-zeroをinstallする。

npm install --save redux-zero

3.storeを修正する。

store.tsを修正します。

store.ts
import * as createStore from "redux-zero"

interface IAppState {
  count: number;
  users: any[] // 必要な場合はuserのinterfaceを作る
}

const initialState: IAppState = {
  count: 1,
  users: []
};

// 「型に呼び出しシグネチャがない式を呼び出すことはできません。」というエラーが起きるので、一度any型の変数に格納
const _createStore: any = createStore;
const store = _createStore(initialState);

export default store;

4.actionを作成する。

Reducerがなくなるので、module.tsをactions.tsとし、actionを作成します。
非同期処理(getUsers)では、HTTP clientにはaxiosを利用し、Random User Generatorよりダミーのユーザーデータを取得しています。

actions.ts
import axios from 'axios';

const actions = ({ setState }: any) => ({
  // async sample
  getUsers: (state: any) => {
    return axios.get(`https://randomuser.me/api/?results=5`)
      .then(payload => ({ users: payload.data.results }))
      .catch(error => ({ error, loading: false }))
  },
  // increment
  increment: (state: any, payload: any) => {
    return { count: state.count + payload };
  },
  // decrement
  decrement: (state: any, payload: any) => {
    return { count: state.count - payload };
  }
});

export default actions;

5.Componentを修正する。

Counter.tsxを修正します。
初期表示時と、ボタンを押したときにそれぞれactionを呼ぶようにします。
今回はContainer.tsxは不要なので削除します。

Counter.tsx
import * as React from "react";
import { Connect } from "redux-zero/react";
import { getActions  }  from 'redux-zero/svelte';

import actions from "./actions";

const mapToProps = ({ count }: any) => ({ count });

interface Props {
  store: any;
}
interface State {}

/**
 * 
 * 
 * @export
 * @class Counter
 * @extends {React.Component}
 */
export default class Counter extends React.Component<Props, State> {
  actions: any;

  constructor(props: Props) {
    super(props);
    // set actions
    this.actions = getActions(props.store, actions);
  }

  componentDidMount(): void {
    this.actions.getUsers();
  }

  render(): JSX.Element {
    return (
      <Connect mapToProps={mapToProps}>
        {({ count, users }: any) => 
          <div>
            <div>
              <p>score: {count}</p>
              <button onClick={e=>this.actions.increment(10)}>increment</button>
              <button onClick={e=>this.actions.decrement(1)}>decrement</button>
            </div>
            <div>
              <ul>
                { users.map((user: any, idx: number) => {
                  return <li key={idx}>{user.email}</li>
                }) }
              </ul>
            </div>
          </div>
        }
      </Connect>
    )
  }
};

6.Index.tsxを修正する。

Counterコンポーネントにstoreを渡すようにします。

Index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import store from './store'

import Counter from './counter/Container'
import { render } from "react-dom";
import { Provider }  from "redux-zero/react";

const App = () => (
  <Provider store={store}>
    <Counter store={store} />
  </Provider>
);

render(<App />, document.getElementById("app"));

以上です。
フォルダは以下のような構成になっていると思います。

.
├── index.html
├── package.json
├── src
│   ├── counter
│   │   ├── actions.ts
│   │   └── Counter.tsx
│   ├── Index.tsx
│   └── store.ts
├── tsconfig.json
└── webpack.config.dev.js

以下のような画面が表示されます。
incremetボタンとdecrementボタンを押下してscoreが増減していれば実装完了です。

React_minimal.png

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?