React初心者がReact×TypeScriptでパーツつくってみた

はじめまして!アドベントカレンダー15日目の記事を担当します、フロントエンドコースのMinamiです。
2022年4月に加入し、9月末にコース修了、10月頃から案件に入らせてもらっています。
今年から導入されたReact課題(成果物:TODOカード作成)の最初の修了者でもあります。
ただし、おんぶにだっこ状態で教えていただいていたので偉いことは言えません💦
そこで「Reactを多少学んだ人が案件に参加したらどうなるのか」「まず何につまづいたのか」について、
環境構築~パーツの作成に至るまでの体験談を中心にまとめてみようかなと思い、
今回の記事制作に至りました!

まずは環境構築

これまで環境構築を自力で成功させた記憶がなく…いつもどこかでつまづいてました。
が!今回は「調べればできる」とのことだったので、初っ端の環境構築をひとりでやってみました。
コマンド打つ度にドキドキしましたね…。

導入したかったものは以下の6つです。

・React
・TypeScript
・storybook
・chromatic
・styled-components
・prettier


styled-componentsの他にも、Reactにcssを導入するやり方は様々ですが、チームではstyled-componentsを主に採用しているみたいなので、それを踏襲する形にしました。
ちなみに、styled-componentsとは「スタイルを適用したコンポーネントを定義」し、タグの代わりにする書き方のことです。

今回の環境構築のコマンド一覧は以下の通りです。

//nodeのバージョンを確認 もし推奨版でなければブラウザで改めてインストール!
$node-v

//yarnのバージョンを確認
$yarn -v

//現在地がこれから作るフォルダを置きたい場所であることを確認して以下のコマンドを入力!
$npx create-react-app (プロジェクト名) --template typescript

$cd (プロジェクト名)

$yarn start

//prettierの導入 やけに時間かかりました
$yarn add -D prettier

//styled-componentsの導入
$yarn add styled-components

$yarn add --dev @types/styled-components

…実は今回も一回失敗してまして💦

npx create-react-app (プロジェクト名)
で実行して、あとから「typescriptっていう指示一回も出してないぞ」と思い…どうにも後戻りできなさそうだったので、諦めてフォルダごと作り直しました。

今回の特筆すべき学びはnpm(Node Package Manager)とnpx(Node Package Execute)の違いですかね。

・npm:node.jsのパッケージを管理する(manage)コマンド
・npx:node.jsのパッケージを実行する(execute)コマンド

ぜひ初案件の人は環境構築担当を引き受けてみてはいかがですか?!

interfaceとtypeってなんだ?!

React(JS)とTypeScriptの大きな違いと言えば「型定義」ですよね。
そもそもTypeScriptとは「JavaScriptでType(型)を扱えるようにしたもの」です。

変数を導入するときはboolean(真偽値)型やstring(文字列)型、number(数値)型といった型を指定していきます。変数の型を定義することで、変数に予期せぬ値が代入された場合エラーが吐かれるので、バグが減るというメリットがあります。その他、保守性を担保するのに非常に有効な手法と言えます。

そして本題の、型定義を行う際に用いるinterfaceとtypeなのですが、大きな違いは無いようです。詳しい違いを説明しているサイトがあったので、参考サイト欄に添付しておきます。

ひとまず、案件では

・当該ファイルで作成している関数コンポーネントに対する型定義はinterfaceで
・各種コンポーネントに対しては
const (コンポーネント名)=styled.(タグ名)<{変数名:型名}>{}
 のように定義する

ということになりました。

StyledComponentsでエラーが出る?!

いつも通りStyledComponentsで書いてみると「なぜエラーが出てくる?!」という事態に。

色々書き方を試して比較してみた結果...
<textContainer/>
ではダメで
<TextContainer/>
としたら、正常に出現しました。

どうやらTypeScriptではStyledComponentsのコンポーネント名は、
キャメルケース(先頭が小文字でその他の単語の頭は大文字)ではなく
パスカルケース(全ての単語の頭が大文字)にしないと認識されないようです。
なんてこった。

.tsxの時はファイル名に注意が必要?!

…パーツは作れた気がするけどstorybookに出現しない?!?!

「storybookに成果物が出現しない」事件を通常比5倍くらいやってしまう私としてはどうにもならず…。
メンバーに聞いてみたところ「自分も最初は出現しなかったが、以下の修正を行ったら出てきた」という口コミが…!

React課題では以下の構造で良かったのですが…

src
└ components
  └ Atoms
   └ Title
     ├ index.jsx
     └ story.jsx


どうやら、この拡張子を.tsxに変えるだけではダメなようです。

src
└ components
  └ Atoms
   └ Title
     ├ Title.tsx
     └ Title.stories.tsx


アドバイスをもとにこれに変えてみたらできました。
なんか最初からつまづいたぞ?!今後に不安が残ります。

propsの受け渡しによりスタイルを変更するやり方

パーツを作っていく中で、レスポンシブ対応を行うためにpropsを受け渡してスタイルを変更する機会が出てきます。
実装当初は「propsを受け渡してclass名で切り替えるのかな?」と思っていたのですが、それ以外にもたくさんの切り替え手段があることを知りました。
今回は、案件の実装でオススメされた「styled componentsでコンポーネントを定義する段階でpropsの受け渡しを行う」書き方を紹介します。

最終的な構造はこちら。今回は簡易的なTitleをイメージしています。
fontSizeというpropsが空だった場合に備え、初期値をlargeにしておきます。

export const Title: FC = ({ fontSize = "large", titleText }: TitleProps) => {
  return (
    <TitleText fontSize={fontSize}>{titleText}</TitleText>
  );
};


ちなみに、ここで登場するFCとは「関数コンポーネント自体の型定義」のことです。
つづいて、これをもとに型定義をするとこちら。

interface TitleProps {
  fontSize?: "small" | "large";
  titleText?: string;
}


最後に、コンポーネント内でのpropsの受け渡しです!まずは、コンポーネントに対して<{fontsize: "small" | "large"}>と記述してから、関数内でfontSizeというpropsを受け取り、三項演算子を用いてスタイルの書き分けをしています。

const TitleText = styled.p<{ fontSize: "small" | "large" }>`
  color: #000000;
  font-weight:700
  ${({ fontSize }) =>
    fontSize === "small" ? `font-size: 32px;` : `font-size: 40px;`}
`;


この他にもたくさんの書き方があるので、もっと調べてみたいと思います。

svgの画像の色が変えられない?!

まずは受け入れの前段階から。

①figmaからassetsをexport
②component直下にIconというフォルダを作成
③package.jsonの”scripts”{}のところに、svgrの最終行を足す


以下、③について具体的に説明します。

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006 -s public",
    "build-storybook": "build-storybook -s public",
    //ここを追加
    "svgr": "npx @svgr/cli -d src/components/atoms/Icon src/utils/assets"
  },


つまり

    "svgr": "npx @svgr/cli -d (jsの格納フォルダのパス) (assetsのフォルダパス)"


を書いた後に、ターミナルで

yarn svgr


すると、svgがjs(もしくはjsx)に成形されて関数化されて

const partsName = (props) => (
  <svg
    width={24}
    height={24}
    fill="none"
    xmlns="#"
    {...props}
  >
    <path
      d="#"
      fill="#000000"
    />
  </svg>
);
export default partsName;


が自動生成され、Iconフォルダの中に格納されるので、styledComponentsでタグと同等の扱いをして導入できるようになるというわけです。
そして、色を変える時はdivタグで囲んで

const IconWrapper = styled.div`
  svg {
    path {
      fill: #c0c0c0;
    }
  }
`;


でOK!
なんでこれを書いたかって?
(jsの格納フォルダのパス)を書き忘れたまま環境構築した私のせいで、svgの色が変わらなかったんですよね...笑えないやらかしです。

忖度してくれるReact vs. そうでもないTS

そんなこんなで、前途多難ですがパーツをぼちぼち作っています。
本題に戻ってみて、React(JS)のみの開発と、ReactベースのTypeScriptでの開発でなにか違う点があるのかについてひと言。
まだどちらも使い始めたばかりなので一概には言えないのですが
忖度してくれるReactとそうでもないTypeScript
という印象を覚えました。なぜなら、上述の通りStyledComponentsのタグの書き方や、ファイル名等で制約があったからです。他にも、classの付け方やテキストの位置(タグの中にテキストを書けず、テキストの外に出す必要があった)などTSが入ってきた途端「ここReactではうまくいったのに、なぜかエラーが出る...」という機会が多かったです。
今後、propsの受け渡しやAPI周りが複雑化するのに備えて勉強しようと思っている今日この頃です。

以上、初心者のゆるゆるブログでした!最後までお読みいただきありがとうございました✨

参考文献・サイト

npmとnpxの違いを理解して使い分けられるようになろう
モダンJavaScriptの基本から始める React実践の教科書 (最新ReactHooks対応) (Informatics&IDEA) | じゃけぇ(岡田 拓巳) |本 | 通販 | Amazon
Amazonでじゃけぇ(岡田 拓巳)のモダンJavaScriptの基本から始める React実践の教科書 (最新ReactHooks対応) (Informatics&IDEA)。アマゾンならポイント還元本が多数。じゃけぇ(岡田 拓巳)作品ほか、お急ぎ便対象商品は当日お届けも可能。またモダンJavaScriptの基本から始める React実践の教科書 (最新ReactHooks対応) (Informatics&IDEA)もアマゾン配送商品なら通常配送無料。
TypeScript で type と interface どっち使うのか問題