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を修正します。
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よりダミーのユーザーデータを取得しています。
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は不要なので削除します。
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を渡すようにします。
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が増減していれば実装完了です。