タイプスクリプト


https://react.vlpt.us/using-typescript/05-ts-redux.html
https://velog.io/@velopert/use-typescript-and-redux-like-a-pro

概要


タイプスクリプトにreduceをインストールする方法についてまとめました.

の手配を

npx create-react-app practice-redux --template typescript
npm install redux react-redux @types/react-redux
react-dredox自体はタイプスクリプトをサポートしていないため、@typesのパッケージを設定する必要があります.

src/modules/counter.ts

// 액션 타입 선언

const INCREASE = 'counter/INCREASE' as const;
const DECREASE = 'counter/DECREASE' as const;
const INCREASE_BY = 'counter/INCREASE_BY' as const;

// 액션 생성 함수 선언
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });
export const increaseBy = (diff: number) => ({
    type: INCREASE_BY,
    payload: diff
});

// 액션 객체들에 대한 타입 설정
type CounterAction =
    | ReturnType<typeof increase>
    | ReturnType<typeof decrease>
    | ReturnType<typeof increaseBy>;

// 상태의 타입 및 초깃값 선언

type CounterState = {
    counter: number;
}

const initialState: CounterState = {
    counter: 0
};
// 리듀서 선언

const counter = (state: CounterState = initialState, action: CounterAction) => {
    const value = state.counter;
    switch (action.type) {
        case INCREASE: {
            return { counter: value + 1 };
        }
        case DECREASE: {
            return { counter: value - 1 };
        }
        case INCREASE_BY: {
            return { counter: value + action.payload }
        }
        default:
            return state;
    }
}

export default counter;
as constを文字列の後ろに貼り付けると、後続のアクション関数が生成されると、文字列ではなく固有のタイプとみなされます.ReturnTypeは、関数が返す戻りタイプを取得することを可能にする.
宣言アクションタイプを作成し、そのタイプのアクション関数を参照します.ペイロードはFSAルールに従うため、動作の値をペイロードに統一することでフォーマットを標準化しているようです.
すべてのアクションシートのタイプを宣言し、Reduserが使用するstateタイプと初期値を宣言した後、Reduserを宣言します.
これにより、Reduceに関連するタイプ、動作に関連する関数、Reduserが1つのファイルに格納されることをDucksモードと呼ぶ.

src/modules/index.ts

import { combineReducers } from 'redux';
import counter from './counter';

const rootReducer = combineReducers({
    counter
});

export default rootReducer;

export type RootState = ReturnType<typeof rootReducer>;
すべてのトカゲ人を団結させ、トカゲ人を構成します.RootState このようなタイプを作成し、エクスポートします.useSelectorを使用する場合は、このタイプが必要です.

ディスプレイ/コンテナ構造


https://blueshw.github.io/2017/06/26/presentaional-component-container-component/
https://fe-churi.tistory.com/34
https://velog.io/@seong-dododo/react-は構成部品と-container構成部品を表します
用途に応じて構成部品を2つの構成部品に分割するモード.
プレゼンテーションコンポーネントはpropsを受信し、直接出力し、目に見える部分を担当します.データを変更したり、放射線を放出したりしません.
コンテナ構成部品は、動作を解放したり、値を変更したりする非表示の部分を担当します.プレゼンテーションコンポーネントにpropsを送信します.

src/components/Counter.tsx

import React from 'react';

type CounterProps = {
  count: number;
  onIncrease: () => void;
  onDecrease: () => void;
  onIncreaseBy: (diff: number) => void;
};

function Counter({
  count,
  onIncrease,
  onDecrease,
  onIncreaseBy
}: CounterProps) {
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
      <button onClick={() => onIncreaseBy(5)}>+5</button>
    </div>
  );
}
カウンタデモ素子を作成します.このプレゼンテーションコンポーネントは、同じコンテナコンポーネントからpropsを渡し、レンダリングを担当します.

src/containers/CounterContainer.tsx

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../modules';
import { increase, decrease, increaseBy } from '../modules/counter';
import Counter from '../components/Counter';

function CounterContainer() {
  const count = useSelector((state: RootState) => state.counter.count);
  const dispatch = useDispatch();

  const onIncrease = () => {
    dispatch(increase());
  };

  const onDecrease = () => {
    dispatch(decrease());
  };

  const onIncreaseBy = (diff: number) => {
    dispatch(increaseBy(diff));
  };

  return (
    <Counter
      count={count}
      onIncrease={onIncrease}
      onDecrease={onDecrease}
      onIncreaseBy={onIncreaseBy}
    />
  );
}

export default CounterContainer;
stateを使用するため、useSelectorを使用してstateを受信し、先ほど指定したRootStateとしてタイプを使用します.

src/App.tsx

import React from 'react';
import CounterContainer from './containers/CounterContainer';

function App() {
  return <CounterContainer />;
}

export default App;

Custom Hookを利用したら


src/hooks/useCounter.tsx

import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../modules';
import { increase, decrease, increaseBy } from '../modules/counter';
import { useCallback } from 'react';

export default function useCounter() {
  const count = useSelector((state: RootState) => state.counter.count);
  const dispatch = useDispatch();

  const onIncrease = useCallback(() => dispatch(increase()), [dispatch]);
  const onDecrease = useCallback(() => dispatch(decrease()), [dispatch]);
  const onIncreaseBy = useCallback(
    (diff: number) => dispatch(increaseBy(diff)),
    [dispatch]
  );

  return {
    count,
    onIncrease,
    onDecrease,
    onIncreaseBy
  };
}
コンテナ構成部品キャラクタを含むCustom Hookを作成し、戻します.

src/components/Counter.tsx

import React from 'react';
import useCounter from '../hooks/useCounter';

function Counter() {
  const { count, onIncrease, onDecrease, onIncreaseBy } = useCounter();

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
      <button onClick={() => onIncreaseBy(5)}>+5</button>
    </div>
  );
}

export default Counter;

src/App.tsx

import React from 'react';
import Counter from './components/Counter';

function App() {
  return <Counter />;
}

export default App;