🐥 React × TypeScript でのメモアプリ作成 #2(Ref, useRef)
作成日: 2022/01/28
4

学習メモ

フォームに入力した文字を表示するには

  • リアルタイムで描写 → useState を使う
  • ボタンを押したときに描写 → useRef を使う

参考リンク:

useRef の Ref とは

  • 要素にRefをアタッチすると、コンポーネント内のどこからでもその要素のDOMにアクセスできるようになる

  • Refの中身はcurrentプロパティの中に格納される

    • 例えばinputタグにアタッチした場合は myRef.current.valueでvalue属性にアクセスできる
  • 便利だけどなにも考えずに使って良いというわけではないらしい

Ref を使いすぎない

最初はアプリ内で「何かを起こす」ために ref を使いがちかもしれません。そんなときは、少し時間をかけて、コンポーネントの階層のどこで状態を保持すべきかについて、よりしっかりと考えてみてください。多くの場合、その状態を「保持する」ための適切な場所は階層のより上位にあることが明らかになるでしょう。

ReactのRefを理解したい

基本的にはあまりRefに頼らないようにしましょう、ということが随所に書かれています。
コンポーネントに親子関係がある場合、基本的に子コンポーネントの詳細は隠蔽されていますが、Refを利用すると親が子の詳細を知らなくてはならない=依存関係が生まれてしまうためですね。

実際に使ってみる

import classes from "./styles/App.module.scss";
import { useState, useRef } from "react";

export const App = () => {
  const inputElement = useRef(null);
  const [text, setText] = useState("");

  const onClickButton = () => {
    setText(inputElement.current.value);
  }

  return(
    <div className={classes.container}>
      <h1 className={classes.title}>簡単メモアプリ</h1>
      <section className={classes.inputArea}>
        <input ref={inputElement} className={classes.inputAreaTextArea} type="text" placeholder="メモを入力" />
        <button onClick={onClickButton} className={classes.inputAreaButton}>追加</button>
      </section>
      <section className={classes.outputArea}>
        <h2 className={classes.outputAreaTitle}>メモ一覧</h2>
        <p className={classes.outputAreaText}>{text}</p>
      </section>
    </div>
  );
};

上記のコードが実行されると、TypeScriptのエラー。初期値がないとのこと

Object is possibly 'null'.

以下を参考に対処
useRefをTypeScriptで使うと Object is possibly 'null'. と怒られる件の対策

  1. useRefにDOMの型をつける
  const inputElement = useRef<HTMLInputElement>(null);

2. nullの場合の処理をいれる

  setText(inputElement.current?.value);

さらにTypeScriptのエラー

Argument of type 'string | undefined' is not assignable to parameter of type 'SetStateAction<string>'.
  Type 'undefined' is not assignable to type 'SetStateAction<string>'.

useStateに型を指定していなかったのが原因らしい

以下を参考に対処
ReactのuseStateでTypeScriptの型を複数指定する方法 useState();

  const [text, setText] = useState<string | null>();

ボタンを押したらテキストが表示されるところまで完成

所感

TypeScriptのエラーに鍛えられている感じがします…🦍🍌