Last active
October 18, 2017 02:10
-
-
Save tetsun/412adb4e894d72309560c524d22b019f to your computer and use it in GitHub Desktop.
- Initialize
create-react-app react-practice1 --scripts-version=react-scripts-ts
- 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
- Edit package.json
"test": "react-scripts-ts test --env=jsdom --setupTestFrameworkScriptFile=raf/polyfill",
- 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
State
のInterfaceを定義する
export interface StoreState {
languageName: string;
enthusiasmLevel: number;
}
- 定数定義をする
- 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;
- 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
};
}
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('!');
}
component
とaction
を繋ぐ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);
state
とaction
を受け取って、新しく作った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;
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment