Skip to content

Instantly share code, notes, and snippets.

@tetsun
Last active October 18, 2017 02:10
Show Gist options
  • Save tetsun/412adb4e894d72309560c524d22b019f to your computer and use it in GitHub Desktop.
Save tetsun/412adb4e894d72309560c524d22b019f to your computer and use it in GitHub Desktop.
  1. Initialize
create-react-app react-practice1 --scripts-version=react-scripts-ts
  1. Install additional packages
npm i -S redux react-redux
npm i -D enzyme enzyme-adapter-react-16 react-addons-test-utils react-test-renderer ts-jest
npm i -D @types/enzyme @types/enzyme-adapter-react-16 @types/react-redux
  1. Edit package.json
    "test": "react-scripts-ts test --env=jsdom --setupTestFrameworkScriptFile=raf/polyfill",
  1. Directory structure of src
tree src

src
├── actions
│   └── index.tsx
├── components
│   ├── Hello.css
│   ├── Hello.test.tsx
│   └── Hello.tsx
├── constants
│   └── index.tsx
├── containers
│   └── Hello.tsx
├── index.css
├── index.tsx
├── logo.svg
├── reducers
│   ├── index.test.tsx
│   └── index.tsx
├── registerServiceWorker.ts
└── types
    └── index.tsx

types

  • StateのInterfaceを定義する
export interface StoreState {
  languageName: string;
  enthusiasmLevel: number;
}

constants

  • 定数定義をする
  • Actionsが返す値
export const INCREMENT_ENTHUSIASM = 'INCREMENT_ENTHUSIASM';
export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM;

export const DECREMENT_ENTHUSIASM = 'DECREMENT_ENTHUSIASM';
export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;

actions

  • Actionを定義する
import * as constants from '../constants';

export interface IncrementEnthusiasm {
  type: constants.INCREMENT_ENTHUSIASM;
}

export interface DecrementEnthusiasm {
  type: constants.DECREMENT_ENTHUSIASM;
}

export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm;

export function incrementEnthusiasm(): IncrementEnthusiasm {
  return {
    type: constants.INCREMENT_ENTHUSIASM
  };
}

export function decrementEnthusiasm(): DecrementEnthusiasm {
  return {
    type: constants.DECREMENT_ENTHUSIASM
  };
}

components

  • Propsを受け取って、JSXを返す
  • Stateを維持しない
import * as React from 'react';
import './Hello.css';

export interface Props {
  name: string;
  enthusiasmLevel?: number;
  onIncrement?: () => void;
  onDecrement?: () => void;
}

function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more ethusiastic. :D');
  }
  
  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
      <div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    </div>
  );
}

export default Hello;

// helpers

function getExclamationMarks(numChars: number) {
  return Array(numChars + 1).join('!');
}

containers

  • componentactionを繋ぐ
  • manStateToProps関数とmapDispatchToState関数を定義し、connectを使って繋ぎこむ
import Hello from '../components/Hello';
import * as actions from '../actions';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
  return {
    enthusiasmLevel,
    name: languageName,
  };
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
  return {
    onIncrement: () => dispatch(actions.incrementEnthusiasm()),
    onDecrement: () => dispatch(actions.decrementEnthusiasm()),
  };
}

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

reducers

  • stateactionを受け取って、新しく作ったstateを返す純関数
import { EnthusiasmAction } from '../actions';
import { StoreState } from '../types/index';
import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants';

export function enthusiasm(state: StoreState, action: EnthusiasmAction): StoreState {
  switch (action.type) {
    case INCREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 };
    case DECREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) };
    default:
      return state;
  }
}

複数のreducerを作る場合

  • combineReducersを利用する
  • containersで定義しているmapStateToPropsで、引数のstateが変わるため修正が必要
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment