LoginSignup
15
11

More than 5 years have passed since last update.

React + Redux + TypeScriptのシンプルなサンプル

Posted at

React+Redux+TypeScriptを始めるにあたってなかなか簡単なサンプルが見つからなかったので、簡単にまとめようと思います。
とりあえず動かすことが目的なので、React+Reduxの詳細については他をあたったほうが良いと思います。

前準備

まずはReactのプロジェクトの骨組み生成のためにcreate-react-appをインストールします。

npm install -g create-react-app

そしたら適当なディレクトリ内でcreate-react-appを使ってredux-sampleという名前のReact+TypeScriptのプロジェクトの骨組みを生成

create-react-app redux-sample --scripts-version=react-scripts-ts

必要な依存関係を追加します。

cd redux-sample
yarn add redux react-redux @types/react-redux
yarn add typescript-fsa typescript-fsa-reducers

コーディング

まずActionを定義します

src/actions/sampleAction.tsx
import actionCreatorFactory from 'typescript-fsa';

const actionCreator = actionCreatorFactory();

export const actions = {
    updateValue: actionCreator<string>('ACTIONS_UPDATE_VALUE')
};

次にStateと現在のStateから新しいStateを生成するためのReducerを定義します。

src/states/sampleState.tsx
import {reducerWithInitialState} from 'typescript-fsa-reducers';
import {actions} from '../actions/sampleAction';

export interface State {
    value: string;
}

const initialState: State = {
    value: '',
};

export const reducer = reducerWithInitialState(initialState)
    .case(actions.updateValue, (state, value) => {
        return Object.assign({}, state, {value});
    });

次にすべてのStateを管理するstoreを定義します。

src/store.tsx
import {combineReducers, createStore} from 'redux';
import {reducer, State} from './states/sampleState';

export type AppState = {
    state: State
};

const store = createStore(
    combineReducers<AppState>({
        state: reducer
    })
);

export default store;

次にデータを表示したりするためのコンポーネントと、それに具体的なコールバック関数などを注入するためのコンテナを定義します。
ここではvalueを入力したらそれを出力するだけのを作ります。

src/components/sampleComponent.tsx
import * as React from 'react';
import {Actions} from '../containers/sampleContainer';
import {State} from '../states/sampleState';


type Props = State & Actions;

export const Component: React.SFC<Props> = (props: Props) => {
    return (
        <div>
            <input
                type="text"
                placeholder="value"
                value={props.value}
                onChange={(e) => props.updateValue(e.target.value)}/><br/>
            {props.value}<br/>
        </div>
    );
};
src/containers/sampleContainer.tsx
import {connect} from 'react-redux';
import {Dispatch} from 'redux';
import {Action} from 'typescript-fsa';
import {actions} from '../actions/sampleAction';
import {Component} from '../components/sampleComponent';
import {AppState} from '../store';

export interface Actions {
    updateValue: (v: string) => Action<string>;
}

function mapStateToProps(appState: AppState) {
    return Object.assign({}, appState.state);
}

function mapDispatchToProps(dispatch: Dispatch<Action<any>>) {
    return {
        updateValue: (v: string) => dispatch(actions.updateValue(v)),
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(Component);

そしたら最後にindex.tsxとApp.tsxを書き換えて終わり

src/app.tsx
import * as React from 'react';
import Container from './containers/sampleContainer';
import './App.css';


class App extends React.Component {
    public render() {
        return (
            <div className="App">
                <Container/>
            </div>
        );
    }
}

export default App;
src/index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import App from './App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
import store from './store';

ReactDOM.render(
    <Provider store={store}>
        <App/>
    </Provider>,
    document.getElementById('root') as HTMLElement
);
registerServiceWorker();
15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11