【React】jsxファイルをtsx(TypeScript)に変換

useReducerを使ったjsxファイルをtsxファイルに変換したのでメモ的に残しておきます。

create-react-app+TypeScript内のコードにjsxファイルを追加したんですが、せっかくなのでTypeScriptに書き換えてみました。

追加したjsxは以下のブログの「sample2: stateが複数」のコードを参考にさせてもらいました。

React hooksを基礎から理解する (useReducer編) - Qiita

変換の流れ

  • ファイル拡張子をjsxからtsxに変更
  • 型推論用にinterfaceを追加
  • ActionTypeの定数を列挙型のenumで定義
  • 関数や引数に型を追加
  • コンパイルエラー箇所を順次修正

元コード

counter.jsx

import React, {useReducer} from 'react'
import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';

const initialState ={
  firstCounter: 0,
  secondCounter: 100
}

const reducerFunc = (countState, action)=> {
  switch (action.type){
    case 'increment1':
      return {...countState, firstCounter: countState.firstCounter + action.value}
    case 'decrement1':
      return {...countState, firstCounter: countState.firstCounter - action.value}
    case 'increment2':
      return {...countState, secondCounter: countState.secondCounter + action.value}
    case 'decrement2':
      return {...countState, secondCounter: countState.secondCounter - action.value}
    case 'reset1':
      return {...countState, firstCounter: initialState.firstCounter}
    case 'reset2':
      return {...countState, secondCounter: initialState.secondCounter}
    default:
      return countState
  }
}
const Counter = () => {
  const [count, dispatch] = useReducer(reducerFunc, initialState)

  return (
    <>
      <h2>カウント:{count.firstCounter}</h2>
      <ButtonGroup color="primary" aria-label="outlined primary button group">
        <Button onClick={()=>dispatch({type: 'increment1', value: 1})}>increment1</Button>
        <Button onClick={()=>dispatch({type: 'decrement1', value: 1})}>decrement1</Button>
        <Button onClick={()=>dispatch({type: 'reset1'})}>reset</Button>
      </ButtonGroup>
      <h2>カウント2:{count.secondCounter}</h2>
      <ButtonGroup color="secondary" aria-label="outlined primary button group">
        <Button onClick={()=>dispatch({type: 'increment2', value: 100})}>increment2</Button>
        <Button onClick={()=>dispatch({type: 'decrement2', value: 100})}>decrement2</Button>
        <Button onClick={()=>dispatch({type: 'reset2'})}>reset</Button>
      </ButtonGroup>
    </>
  )
}

export default Counter

変換したTypeScriptコード

counter.tsx

import React, {useReducer} from 'react'
import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';

interface CountState {
  firstCounter: number,
  secondCounter: number,
};

interface CountAction {
  value: number,
  type: ActionType
}

enum ActionType {
  I_1 = 'increment1',
  D_1 = 'decrement1',
  I_2 = 'increment2',
  D_2 = 'decrement2',
  R_1 = 'reset1',
  R_2 = 'reset2',
}

const initialState ={
  firstCounter: 0,
  secondCounter: 100
}

const reducerFunc:React.Reducer<CountState, CountAction> =  (countState: CountState, action: CountAction)=> {
  switch (action.type){
    case ActionType.I_1:
      return {...countState, firstCounter: countState.firstCounter + action.value}
    case ActionType.D_1:
      return {...countState, firstCounter: countState.firstCounter - action.value}
    case ActionType.I_2:
      return {...countState, secondCounter: countState.secondCounter + action.value}
    case ActionType.D_2:
      return {...countState, secondCounter: countState.secondCounter - action.value}
    case ActionType.R_1:
      return {...countState, firstCounter: initialState.firstCounter}
    case ActionType.R_2:
      return {...countState, secondCounter: initialState.secondCounter}
    default:
      return countState
  }
}

const Counter: React.FC = () => {
  const [count, dispatch] = useReducer(reducerFunc, initialState)

  return (
    <>
      <h2>カウント:{count.firstCounter}</h2>
      <ButtonGroup color="primary" aria-label="outlined primary button group">
        <Button onClick={()=>dispatch({type: ActionType.I_1, value: 1})}>increment1</Button>
        <Button onClick={()=>dispatch({type: ActionType.D_1, value: 1})}>decrement1</Button>
        <Button onClick={()=>dispatch({type: ActionType.R_1, value: 0})}>reset</Button>
      </ButtonGroup>
      <h2>カウント2:{count.secondCounter}</h2>
      <ButtonGroup color="secondary" aria-label="outlined primary button group">
        <Button onClick={()=>dispatch({type: ActionType.I_2, value: 100})}>increment2</Button>
        <Button onClick={()=>dispatch({type: ActionType.D_2, value: 100})}>decrement2</Button>
        <Button onClick={()=>dispatch({type: ActionType.R_2, value: 0})}>reset</Button>
      </ButtonGroup>
    </>
  )
}

export default Counter;