🐥

React TypeScript Cheatsheet

2023/05/05に公開

ReactとTypeScriptでよく使うコードをチートシートにまとめました。

コンポーネント

PropsのTypeを書くパターン

type Props = {
  message: string
};

function Component(props: Props) {
  return (
    <div>{ props.message }</div>
  )
}

//propsの中で一部だけ使う時
function Component({ message }: Props) {
  return (
    <div>{ message }</div>
  )
}

childrenのあるProps

type Props = {
  children: React.ReactNode;
}

function Component(props : Props){
  return (
    <div>{ props.children }</div>
  )
}


//propsの中で一部だけ使う時
function Component({ children }: Props) {
  return (
    <div>{ children }</div>
  )
}

関数式を使ったコンポーネント

関数式を使ったコンポーネントはコンポーネント内で入れ子にするときによく使います。

function Component(){
  const ChildComponent = () => {
    return <div>Child Component</div>
  }
  return (
    <ChildComponent />
  )
}

PropsのTypeを宣言しないパターン

childrenだけあれば良い時などはこれが一番簡単に使えます。

function Component({ children } : { children: React.ReactNode }){
  return (
    <div>{ children }</div>
  )
}

Propsの書き方のパターン

type Props = {
  //文字列
  message: string;

  //数値
  num: number;

  //省略可能な文字列
  optional_message?: string;

  //省略可能な数値
  optional_num?: number;

  //イベントなどのcallback
  eventHandler: () => {};

};

function Component(props: Props){
  return (
    <div>
      <h2>#{props.num} {props.message}</h2>
      <p>{ props.optional_message ?? "省略した時の初期値" }</p>
      <p>{ props.optional_num ?? 10 }</p>
      <button onClick={ props.eventHandler }>ボタン</button>
    </div>
  )
}

useState

stateの初期化と更新のパターンです。オブジェクトのStateはスプレッド構文を使って更新する必要があります。

function Component(){
  const [numberState, setNumberState] = useState(0);
  const [stringState, setStringState] = useState("");
  const [objectState, setObjectState] = useState({
    name: "",
    age: 10
  });

  return (
    <>
      <div>
        {numberState}
        <button onClick={ () => setNumberState(numberState + 1)}>+</button>
      </div>

      <div>
        {stringState}
        <button onClick={ () => setStringState("押された")}>press</button>
      </div>

      <div>
        name={objectState.name}
        age={objectState.age}
        <button 
          onClick={ () => setObjectState({...objectState, name: "Yamada"})}>set name</button>
        <button  
          onClick={ () => setObjectState({...objectState, age: 10})}>set age</button>
      </div>
    </>
  )
}

useState(複雑なオブジェクト)

Stateの中に入れ子で更にオブジェクトがあるような場合はState更新関数をクロージャーで呼び出す形が使いやすいです。

type State = {
  name: string;
  age: number;
  profile: {
    display_name: string;
    message: string;
  }
}
function Component(){

  const [objectState, setObjectState] = useState<State>({
    name: "",
    age: 0,
    profile: {
      display_name: "",
      message: ""
    }
  });

  const onClick = () => {
    setObjectState((value) => {
      value.name = "Yamada";
      value.age = 10;
      value.profile.message = "abc";
      value.profile.display_name = "Yamada";
      return {...value}
    });
  }

  return (
    <div>
      name={objectState.name}
      age={objectState.age}
      profile={objectState.profile.display_name}
      message={objectState.profile.message}
      <button onClick={ onClick }>set name</button>
    </div>
  )
}

条件分岐

if文

条件によって描画内容を変えるコンポーネントのパターン

function ConditionComponent({ flag } : { flag: boolean }){
  if(flag){
    return <p>trueの時のJSX</p>;
  }

  return <p>falseの時のJSX</p>;
}

条件がtrueの時だけ表示される場合はフラグメントを返却する形もあります。

function ConditionComponent({ flag } : { flag: boolean }){
  if(false == flag){
    return <></>
  }

  return <p>条件がtrueなので表示されます</p>;
}

三項演算子

条件で出力内容を変える場合は三項演算子がシンプルに書ける場合があります。

function ConditionComponent({ flag } : { flag: boolean}){
  return (
    <p>{ (flag)  ? "trueの時のJSX" : "falseの時のJSX" }</p>
  )
}

style属性やclassName属性と組み合わせるパターンをよく使います。

//finish=trueでfinishクラスを追加
function TaskItem(props: { task: string, finish: boolean}){
  return (
    <li className={ (props.finish) ? "finish" : ""}>
      { props.task }
    </li>
  )
}

//finish=trueで打ち消し線を追加
function TaskItem(props: { task: string, finish: boolean}){
  return (
    <li style={{ textDecoration: (props.finish) ? "line-through" : "" }}>
      { props.task }
    </li>
  )
}

ループ

Reactでのループは「配列」を「JSXの配列」に変換する処理です。

for文でのループ

function Component(){

  const items = [
    { id: 1, name: "yamada", age: 10},
    { id: 2, name: "suzuki", age: 20},
    { id: 3, name: "satou", age: 30},
  ]

  let elements = []
  for(let item of items){
    elements.push(
      <li key={item.id}>
        { item.name }
      </li>
    )
  }

  return (
    <ul>
    { elements }
    </ul>
  )
}

mapでのループ

function Component(){
  const items = [
    { id: 1, name: "yamada", age: 10},
    { id: 2, name: "suzuki", age: 20},
    { id: 3, name: "satou", age: 30},
  ]

  return (
    <ul>
    { items.map((item) => <li key={item.id}>{ item.name }</li> )}
    </ul>
  )
}

mapと関数式の組み合わせ

function Component(){

  const items = [
    { id: 1, name: "yamada", age: 10},
    { id: 2, name: "suzuki", age: 20},
    { id: 3, name: "satou", age: 30},
  ]

  const renderItem = (item: { id: number, name: string, age: number}) => {
    return <li key={item.id}>{ item.name }</li>
  }

  return (
    <ul>{ items.map((item) => renderItem(item) )}</ul>
  )
}

mapと子コンポーネントの組み合わせ

function Item({item} : { item: { id: number, name: string, age: number}}){
  return <li key={item.id}>{ item.name }</li>
}

function Component(){

  const items = [
    { id: 1, name: "yamada", age: 10},
    { id: 2, name: "suzuki", age: 20},
    { id: 3, name: "satou", age: 30},
  ]

  return (
    <ul>{ items.map((item) => <Item item={item}> )}</ul>
  )
}

初期化処理

ページを開いた時一度だけ処理をするなどの初期化処理にはuseEffect()を使います。

import { useEffect, useState } from "react";

function Component(){

  const [message, setMessage] = useState("");

  useEffect(() => {
    setMessage("初期化されました")
  }, [])

  return (
    <p>{message}</p>
  )
}

useEffectを使うパターンはいくつかあります

  1. バックエンドとの通信を行う
  2. JavaScriptのライブラリを利用する

jQueryを使う

jQueryを使う場合はDOMの準備が完了している場合があるため、useEffect()と組み合わせる場合があります。

import { useEffect } from "react";
import $ from 'jquery';

function Component(){

  useEffect(() => {
    $("#message").html("jQueryで書き換え")
  }, [])

  return (
    <p id="message"></p>
  )
}

フォーム(controlled)

controlledなフォームとはstateで入力内容を保持し、onchangeでstateを書き換える手法です。

function Component2(){

  const [text, setText] = useState("");

  return (
    <>
      <input 
        type="text" 
        value={text} 
        onChange={ (event) => setText(event.target.value) } />

      <p>input={text}</p>
    </>
  )

}

入力内容をリアルタイムで取得することが出来ます。パフォーマンスは入力の度に書き換えが発生するため遅くなります。

テキスト、ラジオ、セレクトボックスのControlledなパターン

controlledな形で複数の入力項目があるコンポーネントの場合、Stateやコードが複雑になる傾向があります。

type Values = {
	text: string;
	radio: number;
	select: number
}

function Component(){

  const [values, setValues] = useState<Values>({
    text: "",
    radio: 0,
    select: 0
  });

  const updateFormValue = <K extends keyof Values>(key: K, value: Values[K]) => {
    values[key] = value
    setValues({...values})
  }

  return (
    <>
      <div>
        <h3>テキスト</h3>
        <input type="text" value={values.text} onChange={ (event) => updateFormValue("text", event.target.value) } />
        <p>input={values.text}</p>
      </div>

      <div>
        <h3>ラジオ</h3>
        <input type="radio" name="input-radio" value={1} onChange={ (event) => updateFormValue("radio", parseInt(event.target.value)) } />
        <input type="radio" name="input-radio" value={2} onChange={ (event) => updateFormValue("radio", parseInt(event.target.value)) } />
        <input type="radio" name="input-radio" value={3} onChange={ (event) => updateFormValue("radio", parseInt(event.target.value)) } />
        <p>radio={values.radio}</p>
      </div>

      <div>
        <h3>セレクト</h3>
        <select
          value={values.select}
          onChange={ (event) => updateFormValue("select", parseInt(event.target.value)) }
          >
          <option>----</option>
          <option value={1}>item 1</option>
          <option value={2}>item 2</option>
          <option value={3}>item 3</option>
        </select>
        <p>select={values.select}</p>
      </div>

    </>
  )

}
  1. フォーム全体を取り扱うStateを作成する(type Values)
  2. 各フォームを更新する関数を共通化する(updateFormValue関数)
  3. 各フォームコントロールでvalueとonChangeを設定する

という流れで作ることが出来ます。

フォーム(uncontrolled)

uncontrolledなフォームはフォーム全体をStateでまとめず、ボタン押下などのタイミングで作成する方法です。

function Component(){

  const handleSubmit = (e:React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const formData = new FormData(e.currentTarget);
    console.log("text=" + formData.get("text"));
    console.log("radio=" + formData.get("radio"));
    console.log("select=" + formData.get("select"));
  }

  return (
    <>
      <form onSubmit={ handleSubmit }>
        <div>
          <h3>テキスト</h3>
          <input type="text" name="text" />
        </div>

        <div>
          <h3>ラジオ</h3>
          <input type="radio" name="radio" value={1} />
          <input type="radio" name="radio" value={2} />
          <input type="radio" name="radio" value={3} />
        </div>

        <div>
          <h3>セレクト</h3>
          <select name="select">
            <option>----</option>
            <option value={1}>item 1</option>
            <option value={2}>item 2</option>
            <option value={3}>item 3</option>
          </select>
        </div>

        <input type="submit" value="submit" />
      </form>

    </>
  )

}

<form>を用意し、onSubmit()で全てを処理するパターンです。

入力内容をリアルタイムで取得出来ませんが、組み込みは高速です。

フォームコントロールにはname属性を指定する必要があります。

GitHubで編集を提案

Discussion