20210613のReactに関する記事は10件です。

Reactとはなにか、Reactの開発からデプロイまでの流れ

はじめに 前回の記事[1]でデプロイまでできたのですが、いまいち何をしているのか理解できませんでした。 そもそもReactは何をしているのか、どのような流れでデプロイするのかをまとめたいと思います。 Reactは何をしているのか Reactとはjavascriptのライブラリという風に書かれていることが多いと思います。 ただ、C言語の#includeライブラリ名.hみたいにインクルードすればいいのかいうと全く違います。 個人的にはHTMLを値として持てるjavascriptを使ってプログラムする仕組みだと思っています。 この表現は正確ではないと多くの人に言われそうですが、ライブラリだと思ってると認識のずれが生じます。 たぶんライブラリとかフレームワークの定義が統一されていないからこういうことになるんでしょう。 そもそもReactは単体では動きません。 大きく分けて4つのものに構成されています[2]。 javascript 当然javascriptの知識は知らないとだめです。nodejsとかの区別は一旦置いといていいです。 JSX これがReactの中枢を担っている気がします。 JSXはjavascriptの拡張言語です。 一番の違いはDOMを値として扱えることです。 定数などに代入したり、DOMそのものを返り値とすることが出来ます。 そこさえ押さえておけば仕組みは分かります。 Babel JSXはそうすると楽だよねって勝手に作った拡張言語です。 サーバーにアップして使う際にはjavascriptでないと当然動きません。 この拡張言語をjavascriptに変換するのがBabelです。 またjavascriptの標準的な書き方がES5からES6に移行しました。 この2つは割と大きな違いがあり、かつすべてのブラウザがES6に対応しているわけではありません。 下位互換性を持たせるためにすべてのjavascriptをES5にするべきです。 このES5への変換もBabelが担っています。 イメージとしては JSX→javascript→javascript(ES5) みたいな流れでしょうか。 逐次的に変換しているのか、まとめて変換しているのかは分かりませんがこんな理解でいいでしょう。 要するにJSXのjavascriptへの変換、javascript(ES5)への変換をしてくれるツールです。 webpack [2]より引用 webpackは、JavaScriptを依存関係を考慮してひとまとめにしてくれるツール  要するに散らかってるjavascriptをひとまとめにしてくれるというものです。  まとめたjavascriptをBabelに通します。 この4つによるプログラム生成の仕組みを前提として動いているのがReactです。 Reactを使うということはこれらの仕組みを使うということと同義です。 ライブラリとしてのReactはこれらの仕組みの上に成り立ったものです。 webエンジニアが直接触るのはJSXだけですが、ここら辺は理解しておきましょう。 デプロイまでの流れ 結局JSXプログラムを書いたらどうすればいいのでしょうか。 HTML/CSS/javascriptだったらサーバーに置いたらOKです。 Cなどのコンパイル言語ならコンパイルして実行すればいいです。 pythonなどのスクリプト言語なら書いてすぐ実行できます。 しかしJSXではjavascriptをまとめて変換しないといけません。 頭ではわかってもコマンド上はどうなるのでしょうか。 そのための環境構築コマンドとしてcreate-react-appコマンドがあります。 このコマンドによってwebpack、babel、reactライブラリなどがプロジェクトディレクトリ配下のnodemodulesディレクトリにダウンロードされます。 これらをNode.jsのアプリケーションとして動かす場合は yarn start とすればローカルで立ち上げることが出来ます[3]。 しかし、webサーバーにアップロードする場合は変換しなければなりません。 この変換の作業を一般的にはビルドと呼ばれています。 makefileとかでもビルドという言葉使っていた気がします。 ここでのビルドはソースコードを使える状態に変換するようなニュアンスでしょう。 コンパイルと言い換えてもあまり差し支えないように感じます。 もちろんCのコンパイルのようにコードをバイナリに変換してるわけではありません。 しかし、webサーバーで使える形式に変えているのです。 コマンド上では yarn build などでビルド出来ますが、実際にはjsonファイルのスクリプトが実行されています。 このファイルをwebサーバー上におけばデプロイ完了というわけです。 僕の場合は yarn deploy でビルドとデプロイ同時にやってくれます。 あとこのサイト[4]が割と流れを丁寧に説明してくれているので読んでおくことをお勧めします。 おわりに React複雑すぎる。 こんなの一発で分かる訳ないでしょうと思っちゃいますね。 JSXの考え自体は好きなんですが、この仕組み自体をもう少し抽象化して欲しいです。 参考文献 [1]:GitHub Pages で最小構成のreactのhelloworldをデプロイしてみた [2]:Reactをなんとなく理解できるようになるまでのステップ [3]:Reactの基本的な仕組みを理解しよう (1/4) [4]:reactの基本がnode.jsだと聞いたのですがどういうことですか?書き方が同じということですか?まだ全くの初心者なのでやさしく教えていただけると助かります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactにおけるコンポーネントのメモ

タグを関数ごとに分ける Reactは内部の仮想DOMレンダラーを使い、 タグを関数ごとに分けることが出来ます。 こんな感じ <div class="container mt-4"> <div id="root">wait</div> </div> <script type="text/babel" /> let dom = document.querySelector("#root") let message = "message variant" function Welcome(props) { return <div className={props.alert}> <p className={props.fontSize}>Hello React! {props.name}</p> </div> } let el =( <div> <Welcome /> </div> ) ReactDOM.render(el, dom) </script> こうすると、 function Welcome(props) {} この関数の中身がタグに描画されるみたいですよ。 もちろん、関数である以上、 引数も取れます <div class="container mt-4"> <div id="root">wait</div> </div> <script type="text/babel" /> let dom = document.querySelector("#root") let message = "message variant" function Welcome(props) { return <div> <p>Hello React!</p> </div> } let el =( <div> <Welcome name="Taro" fontSize="h2" alert="alert alert-primary" /> <Welcome name="Hanako" fontSize="h5" alert="alert alert-dark" /> </div> ) ReactDOM.render(el, dom) </script> こんな感じみたいですね 参考図書 React.js&Next.js超入門 掌田 津耶乃 https://www.amazon.co.jp/React-js-Next-js%E8%B6%85%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798056928
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

@xstate/testはどう使うのか?

問題 @xstate/testのページをパッと見た限りだと「あーmachineがあって、それに沿ってテストするやつね?」って思うけど実は違う。 多分全ての人が初めにする勘違い @xstate/testはxstateのmachineをテストする為(だけ)ではない。 テストする対象はxstateを使っていないただのページでも良いし、ただのJavascriptのコードでも良いし、@testing-library/reactでも良いし、puppeteerでもcypressでもいい。 createModel これは確かにxstateのmachineが必要だけど、このmachineをテストしているわけじゃない(!!!)。 パラメータとして渡しているこのmachineはテスト対象ではなくて、ユーザーとしてどういう動きをするだろうかのpathsを作るためのmachine。 (xstateのmachineをテストしているのなら、得てして同じものになりがち、だがもう一度言うがこのmachineはテスト対象ではない) It's not "test code and implementation code" - it's test code and test code. The state machine describes the flows of the system under test, with assertions (in meta.test) that make sure each visited state is actually in their expected state. リンク I've struggled to understand this too. It made more sense once I read this tweet. The goal is NOT to import your machine and generate tests from it. The goal is to write a NEW machine that acts like your users will, and test that. According to the xstate advice, you should not be trying to directly instrument your app's machine in the test files you create. リンク リンク Note that this finite state machine is used only for testing, and not in our actual application — this is an important principle of model-based testing, because it represents how the user expects the app to behave, and not its actual implementation details. The app doesn’t necessarily need to be created with finite state machines in mind (although it’s a very helpful practice). リンク 結局何をテストしているのか? testPath.test(testContext)ともあるように、ここに渡している何か(testContext)、をcreateModelに渡したmachineに記載しているmeta: {test: {...}}で検証している。 const toggleMachine = createMachine({ ... ... inactive: { on: { /* ... */ }, meta: { // path.test(page)に渡されたものが、まるっと全部最初のパラメータとして受け取れる // path.test([a, b, c])とすれば([a, b, c]) => {} として // path.test({a: 1, b: 2})とすれば({a, b}) => {} として test: async (page) => { await page.waitFor('input:checked'); } } }, // 何度も言うが、このtoggleMachineはテスト対象ではない const toggleModel = createModel(toggleMachine).withEvents({ ... }) ... ... it(path.description, async () => { // 渡す値は自由 // テストに必要なものは何でも突っ込んで、実際のテスト時に使える // ここではこのpageがテスト対象(puppeteerのページ) await path.test(page); }); 前提条件 → アクション(操作) ​→ 事後条件 /(precondition → action → postcondition) 例えば、modalが開くボタンが1つだけあるページだとしても(xstate有無不問) 初期表示(modal表示なし) ボタンを押す(modal表示) modal閉じるボタンを押す(modal非表示) というユーザーとして起こすだろう操作がある。これをcreateModelに渡すmachineとして定義してやって、 getShortestPathPlans getSimplePathPlans から最終的にpathsを自動生成して、想定できる全てのルートを通るテストを行うということが@xstate/testの趣旨(だと今の所理解してる)。 実際はもっと複雑なprecondition → action → postconditionがあるはずで、ダイアログが出る単純なページでさえもその複雑さが分かる createModelの使い方 テスト対象の何かがある(切り出したコンポーネントだったり、ページ自体だったり、Javascriptのクラスオブジェクトだったり) 想定しうるユーザーとしてのprecondition → action(= event) → postconditionをmachineで表現する このmachineのmeta -> testに実際のテストを書く createModelにそのmachineを渡す 加えてwithEventsに各アクション時にはどういう操作が必要かを書く pathにテスト対象を渡す テストを実際にするにあたって テスト対象がxstateのmachineだったとして... services invokeするからには何らかの結果を期待しているわけだけど、多くの場合、他のサービスとのデータ連携だったりもする。 こういう場合はとてもテストがしづらいので、service単体でテストは終えておいて、テストをする際はmachineを使うコンポーネント、ページ単位で切り出しておいて、該当のサービスは無効化するようなり処理をして、単純にprecondition → action → postconditionがうまく画面の表示と合うかだけをテストするようにする。 テスト対象の何か // withConfigで渡すオブジェクトはコンポーネントのPropsにしておけばtest、production用と分けなくて良くなる useMachine(machine.withConfig({ services: { someService: () => { // ここでうまいこと無効化する } } })) actions serviceと同様、単体でテスト + コンポーネントレベルなどのテストではうまいこと無効化する。 guards 大抵はactionでcontextが変更された値を評価すると思うので、上の事が出来ていれば大丈夫じゃないかと。 activities これも多分同じ。 meta: {test: { ... }} const toggleMachine = createMachine({ id: 'toggle', initial: 'inactive', states: { inactive: { on: { /* ... */ }, meta: { test: async (page) => { await page.waitFor('input:checked'); } } }, 最初これを見た時は「おいおい、テストコードを成果物に埋め込むのか?」と思って、MachineConfigで切り出してみたりして実際のコードと、テスト用のコードと振り分けたりしてたけど、より複雑になっていく一方で「こんな使い方なわけがない...」と思って色々調べてたらやっぱり同じ様な事に悩んでる人がいて、よくよく読んでいくとやっぱり前提条件としてcreateModel(machine)のmachineがテスト対象ではないと分かった。 @xstate/testのページ自体あっさりと書いてあるし、ネットでも@xstate/testを説明しているページがそんなに無いので、理解するまでに相当時間がかかった。 リンク
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTML/CSS/Javascript/JSXのコメントアウトの方法

はじめに コメントアウトの方法をよく忘れるのでまとめておきます こちら[1][2]を参考にさせていただきました。 2021/6/13追記 コメントで指摘されたHTMLのコメントアウトについて修正しました。 コメントアウト 言語 1行コメントアウト 複数行コメントアウト HTML <!–- コメント -–> 左と同じ CSS /* コメント */ 左と同じ javascript //コメント /* コメント*/ JSX {//コメント} {/* コメント*/} おわりに HTMLとCSSのコメントアウトめんどくさい。 それではまた。 参考文献 [1]:【HTML】コメントアウトの書き方!注意点や便利な使い方も紹介 [2]:今更聞けない JSX のコメントアウトの構文
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ReactのHelloWorldはどのようにできているのかを解析する

はじめに 前回の記事[1]で最小構成のreactのHelloWorldをデプロイした。 言われるがままやっただけで理解できていないので、1つ1つ理解していく。 知識としてはprogateでHTML/CSS/javascript/Reactをやった程度。 正直Reactがどういうシステムなのか分かっていないので、現段階ではどのように動かすか理解できればいい。 なぜそうなるのかはあとで後日考察する。 プログラム index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <!--ディスプレイに合わせて表示--> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!--アドレスバーの背景色を変更(OS/ブラウザに依存)--> <meta name="theme-color" content="#000000" /> <title>React App</title> </head> <body> <div id="root"></div> </body> </html> index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); App.js function App() { return ( <div className="App"> Hello,World </div> ); } export default App; 解析 コードの参照順としてはindex.html→index.js→App.jsとなっている。indexの部分はどのプログラムにもありそうだが、App.jsは他の名前とかにするんだろうか。最小構成だからこれで済んでいるが、おそらくApp.jsで他の作成したコンポーネントを呼び出してさらにネストしていくのだと思われる。 index.html headタグはコメントに書いてある通り。 普通のhtmlだが、divタグにid="root"とある。 <div id="root"></div> これがあとあと必要な処理のよう。 index.js import React from 'react'; import ReactDOM from 'react-dom'; importはpythonとかでも似たようなことしてますね。 厳密な構文を探したところ、このサイト[2]に載ってました。 import {インポートするエクスポートの名前} from "モジュールの名前"; 中括弧はexport defaultされたものにはいらないようです[3] エクスポートはおそらくApp.jsの最後にもあったやつ。 これも調べたところ載ってました[4]。 とりあえずJavaScript モジュールを作成するために使用する文という認識で良さそうです。 export default モジュールの名前; 何がデフォルトなのかを調べたところ、こちらのサイト[5]に載ってました。 このjavascriptファイルのデフォルトとして後ろに続く名前のモジュールをエクスポートしますよという意味のよう。 あくまでモジュールの名前なのでエクスポートの名前はimport側で勝手に変えれるよう。 実施にエクスポート名をApp以外にしても普通に動作しました。 長くなりましたが1文目はreactというモジュールをReactという名前でインポートしますよという意味。 となると別にReactの部分は変えても良さそうだが、慣習的に同じにしてるってことだろう。2文目も同様。 ただ、こういうパッケージはnpmかyarnでプロジェクトディレクトリ内にnodemodules内にダウンロードされています。 特に指定しなかったらnodemodulesからとってくるという認識でいいのかな? import App from './App'; さっきとほぼ同じですが、なんかパスの指定っぽくなってますね。 [2]に全く同じような構文はなくて、ファイルの拡張子まで指定しているやつはあります。 import {App} from './App.js'; これなら構文通りなんですが微妙に違います。 思うにこれはモジュールじゃなくてファイルそのものからインポートしてきています。 App.jsではモジュール名をAppとしてエクスポートしているので import 自分の好きな名前 from "モジュール名までのパス"; みたいな感じじゃないでしょうか。 App.jsをディレクトリに入れてパスを変更したところちゃんと表示されました。 パスを指定しなければnodemodulesを見に行って、それ以外は相対パス指定してねみたいな感じでしょうか。 また気になったので./App.jsに変えてみたところ動作しました。 これはファイルそのものを参照しても大丈夫ということなのか、ただ拡張子省略できますよのどっちの意味なんだろう。 これ以上突っ込むと沼にはまりそうなので拡張子は省略して書けますということにしておきましょう。 ReactDOM.render(); これが全く分かりません。 なんか出力してるんだろうなーぐらいの認識です。 公式リファレンス[6]によるオプションを省いた構文を載せます。 ReactDOM.render(element, container) リファレンスでは渡されたcontainerのDOMにReact要素をレンダーするという風に書いてあります。 まずレンダリングの言葉の定義を考えます。 [7]の内容の一部を下記に要約引用します。 レンダリングとは変更前と変更後の仮想DOMの差分を比較し、差分を検知することで仮想DOMを再構築すること。 DOMには変更が直接反映されるリアルDOM(たぶん仮称)と仮想DOMが存在する。 Reactでは2つの仮想DOMがあり、その差分をリアルDOMに反映させる。 要するにこの関数を用いて差分を実際のDOMに反映させているということでしょう。 よくよく考えてみれば結局HTML/CSS/javascriptなんだからそのファイルをいじることが出力の変更になる。 ずっとCでprintfしたりC++でcoutしてたので盲点だった。 つまりこの関数は実際のDOMを変更するための関数という認識でいいでしょう。 ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); とするとこのReact.StrictModeで囲まれているのがReact要素(component)、document.getElementById('root')がcontainerだ。 [8]によると問題のある書き方を特定するためのモードのよう。 gcc -Wallみたいな感じだろうか。 とりあえずこれはこういうものだと思ってとりあえずつけておけば良さそう。 そうなるとが残るのでこれがReact要素ということでしょう。 この関数は構文上複数のコンポーネントを持てない。 だからApp.jsのようなコンポーネントを集約するためのコンポーネントを作成してこの関数にまとめて渡すのでしょう。 次はdocument.getElementById('root')です。 まずはこの関数の構文が知りたいので調べたところ、こちらに[9]載っていました var element = document.getElementById(id); idを引数としてElementオブジェクトを返すようです。 Element オブジェクトは調べましたがよく分かりません。 要するにこのidで特定された場所を返すような関数なんでしょう。 今気づきましたがCの癖で関数と呼んでますがメソッドですね。 正直かなり違いますが直すのめんどくさいので次から直すので許してください。 となるとcomponentは各コンポーネントの内容、containerはそれをどこに挿入するかを表してるみたいな感じでしょうか。 たぶん正確には違うと思いますが、構成を理解してプログラムが書ければいいのでこういう理解でいいでしょう。 そうなるとindex.htmlとindex.jsはほとんどいじらなくて良さそうですね。 こういうこと誰も書いてないですが、みんな理解せずになんとなくで書けるんでしょうか? おまじないにしても最低限理解できないとフォルダ構成とかも変えられない気がするんですが。 しかし、こうやって見てみると見事なまでにカプセル化されてますね。 1つのファイルが1つの機能を持つようにという意思も感じられます。 なんでこんなにファイルを分けるんだと思ってましたが、こういったポリシーがあったのでしょうね。 App.js export default App; これは先ほど説明した通りデフォルトでAppというモジュール名でエクスポートするという文です。 Reactの方針として1つのファイルには1つの機能が理想でしょうから、基本的にはデフォルトでいい気がしますね。 function App() { return ( <div className="App"> Hello,World </div> ); } 関数Appを定義しています。 返り値としてDOMを返しているということでしょう。 progateでは class App extends React.Component { } となっていたのですが、関数でもいいんでしょうか。 まあそこは実際に作る際に考えます。 おわりに 今回はrecctのHelloworldはどのように作られているのか解析しました。 やっとスタートラインに立てた気がします。 Reactではjavascriptよりも強くオブジェクト指向が意識されていますね。 それではまた。 参考文献 [1]:GitHub Pages で最小構成のreactのhelloworldをデプロイしてみた [2]:import [3]:ES2015 (ES6) の import や export (default)(React基礎講座4) [4]:export [5]:export defaultってなんだろう [6]:ReactDOM [7]:Reactのレンダリングと描画の違いを整理する [8]:React.StrictModeがあぶり出す意外な問題点 [9]:Document.getElementById()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactコンポーネント基礎

説明したいこと Reactのコンポーネントとは コンポーネントの種類 コンポーネントの使い分け 単純なコンポーネントの作成方法 Reactとは Facebookが開発したコンポーネント指向のUI構築ライブラリです。 React公式サイト コンポーネントとは Reactはコンポーネントと呼ばれるUIの部品を組み合わせてアプリを構築していきます。コンポーネントは値を受け取ることができ、受け取った値により見た目、動きを変えます。 適度な粒度で独立したコンポーネントを作成していくことで、アプリ内の様々な箇所で使い回す事ができ、見やすいコードになると思います。 Reactでアプリを開発する際はこの、コンポーネントを 作っていくことが大半の作業になるかと思います。 Reactのコンポーネントには大きく分けて以下の2つの作り方があります。 クラスコンポーネント (クラスでコンポーネントを定義) 関数コンポーネント (関数でコンポーネントを定義) ですが、今からReactを始める場合は関数コンポーネントでの作り方だけ分かっていれば問題ないです。 というのも、以前までClass Componentでしかできないことがあったのですが、Hooksと呼ばれるものの登場により、できることに差がなくなったからです。 この記事の中では、関数コンポーネントのみを対象に説明していきます。 コンポーネントの作り方 用語 Props : コンポーネントに渡されるパラメータ State : コンポーネントが持つ状態 JSX : コンポーネントのUIの記述をする コンポーネントの種類 Reactのコンポーネントには以下の2種類があります Presentational Component Container Component Presentational Componentは見た目の定義だけをし、JSXを多く持ちます。 Container Componentはコンポーネントのロジックを定義します。 これらは、もともとはReduxと呼ばれるReactの状態管理を行うライブラリで用いられていたものですが、Reduxを使用していなくてもコンポーネントを見た目とロジックで分けることでコードが見やすく、管理もしやすくなると感じています。 呼び方としてははPresentational Componentをコンポーネント、Container Componentはコンテナと呼ぶことが多い気がします。 コンポーネントを作成してみる 今からこんな感じの、押した回数によってカウントが増えていくコンポーネントを例として作成します。 環境の構築 この記事では割愛させてもらいます?‍♂️ 基本的にはcreate-react-appで作成されたプロジェクトでTypeScriptを使用していくことを想定してます。 Presentational Componentの作成 コンポーネントを作成する際はまず、見た目を作成していきます。 ここでは、ボタンとクリック回数を表示するラベルという、goodとbadで共通した部品を作ります。 RateButton.tsx import React, { FC } from "react"; // コンポーネントのProps(パラメータ)の型を定義 type RateButtonProps = { buttonText: string; clickedNumber: number; onClick: () => void; }; // 関数コンポーネント export const RateButton: FC<RateButtonProps> = (props) => { const { buttonText, clickedNumber, onClick } = props; return ( <> <button onClick={onClick}>{buttonText}</button> <label> {clickedNumber}</label> </> ); }; このファイルを作成するだけでは画面上に表示されないので一時的に、App.tsxをこんな感じにします。 App.tsx import "./styles.css"; import { RateButton } from "./RateButton"; export default function App() { return ( <> {/* とりあえず表示するために固定を渡している */} <RateButton buttonText='good?' clickedNumber={0} onClick={() => console.log('clicked')} /> </> ); } ※index.tsxがApp.tsxを読み込んで、その内容を表示する流れになっているのですが、細かい箇所は省略します。 そうすると、以下のコンポーネントが表示されます。 Container Componentの作成 今のままだと、クリックしても何も反応しないものになってしまうので コンテナを使用してロジックを書いていきます。 BadButtonContainer.tsx import React, { FC, useState } from "react"; import { RateButton } from "./RateButton"; type BadButtonContainerProps = { buttonText: string; }; export const BadButtonContainer: FC<BadButtonContainerProps> = (props) => { // コンポーネントが持つ State(状態) const [badNumber, setBadNumber] = useState<number>(0); const addBadNumber = () => { setBadNumber((preState) => preState + 1); }; return ( <RateButton {...props} clickedNumber={badNumber} onClick={addBadNumber} /> ); }; コード上で出てきているuseState()に関してですが、これは関数コンポーネントでState(状態)を保持できるようにした機能です。今回はクリックしたという動作に合わせてStateが変化していくのでコンテナにStateを持たせています。 useState これでBadボタンの動きまで作成できました。GoodボタンもベースとなるRateButtonは同じでStateの動きが異なるだけなので同様に作成します。 GoodButtonContainer.tsx import React, { FC, useState } from "react"; import { RateButton } from "./RateButton"; type GoodButtonContainerProps = { buttonText: string; }; export const GoodButtonContainer: FC<GoodButtonContainerProps> = (props) => { const [goodNumber, setGoodNumber] = useState<number>(0); const addGoodNumber = () => { setGoodNumber((preState) => preState + 1); }; return ( <RateButton {...props} clickedNumber={goodNumber} onClick={addGoodNumber} /> ); }; あとはApp.tsxを以下のように修正します。 App.tsx import React from 'react'; import { BadButtonContainer } from "./BadButtonContainer"; import { GoodButtonContainer } from "./GoodButtonContainer"; export default function App() { return ( <> <GoodButtonContainer buttonText="good?" /> <BadButtonContainer buttonText="bad?" /> </> ); } これで完成です。 まとめ この記事ではコンポーネントのみを対象に説明しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React初心者がまとめたReact超基礎

はじめに Reactを半年ほど触ってきたので自身のまとめも含め作成します。 説明したいこと Reactのコンポーネントとは コンポーネントの種類 コンポーネントの使い分け 単純なコンポーネントの作成方法 Reactとは Facebookが開発したコンポーネント指向のUI構築ライブラリです。 React公式サイト コンポーネントとは Reactはコンポーネントと呼ばれるUIの部品を組み合わせてアプリを構築していきます。コンポーネントは値を受け取ることができ、受け取った値により見た目、動きを変えます。 適度な粒度で独立したコンポーネントを作成していくことで、アプリ内の様々な箇所で使い回す事ができ、見やすいコードになると思います。 Reactでアプリを開発する際はこの、コンポーネントを 作っていくことが大半の作業になるかと思います。 Reactのコンポーネントには大きく分けて以下の2つの作り方があります。 クラスコンポーネント (クラスでコンポーネントを定義) 関数コンポーネント (関数でコンポーネントを定義) ですが、今からReactを始める場合は関数コンポーネントでの作り方だけ分かっていれば問題ないです。 というのも、以前までClass Componentでしかできないことがあったのですが、Hooksと呼ばれるものの登場により、できることに差がなくなったからです。 この記事の中では、関数コンポーネントのみを対象に説明していきます。 コンポーネントの作り方 用語 Props : コンポーネントに渡されるパラメータ State : コンポーネントが持つ状態 JSX : コンポーネントのUIの記述をする コンポーネントの種類 Reactのコンポーネントには以下の2種類があります Presentational Component Container Component Presentational Componentは見た目の定義だけをし、JSXを多く持ちます。 Container Componentはコンポーネントのロジックを定義します。 これらは、もともとはReduxと呼ばれるReactの状態管理を行うライブラリで用いられていたものですが、Reduxを使用していなくてもコンポーネントを見た目とロジックで分けることでコードが見やすく、管理もしやすくなると感じています。 呼び方としてははPresentational Componentをコンポーネント、Container Componentはコンテナと呼ぶことが多い気がします。 コンポーネントを作成してみる 今からこんな感じの、押した回数によってカウントが増えていくコンポーネントを例として作成します。 環境の構築 この記事では割愛させてもらいます?‍♂️ 基本的にはcreate-react-appで作成されたプロジェクトでTypeScriptを使用していくことを想定してます。 Presentational Componentの作成 コンポーネントを作成する際はまず、見た目を作成していきます。 ここでは、ボタンとクリック回数を表示するラベルという、goodとbadで共通した部品を作ります。 RateButton.tsx import React, { FC } from "react"; // コンポーネントのProps(パラメータ)の型を定義 type RateButtonProps = { buttonText: string; clickedNumber: number; onClick: () => void; }; // 関数コンポーネント export const RateButton: FC<RateButtonProps> = (props) => { const { buttonText, clickedNumber, onClick } = props; return ( <> <button onClick={onClick}>{buttonText}</button> <label> {clickedNumber}</label> </> ); }; このファイルを作成するだけでは画面上に表示されないので一時的に、App.tsxをこんな感じにします。 App.tsx import "./styles.css"; import { RateButton } from "./RateButton"; export default function App() { return ( <> {/* とりあえず表示するために固定を渡している */} <RateButton buttonText='good?' clickedNumber={0} onClick={() => console.log('clicked')} /> </> ); } ※index.tsxがApp.tsxを読み込んで、その内容を表示する流れになっているのですが、細かい箇所は省略します。 そうすると、以下のコンポーネントが表示されます。 Container Componentの作成 今のままだと、クリックしても何も反応しないものになってしまうので コンテナを使用してロジックを書いていきます。 BadButtonContainer.tsx import React, { FC, useState } from "react"; import { RateButton } from "./RateButton"; type BadButtonContainerProps = { buttonText: string; }; export const BadButtonContainer: FC<BadButtonContainerProps> = (props) => { // コンポーネントが持つ State(状態) const [badNumber, setBadNumber] = useState<number>(0); const addBadNumber = () => { setBadNumber((preState) => preState + 1); }; return ( <RateButton {...props} clickedNumber={badNumber} onClick={addBadNumber} /> ); }; コード上で出てきているuseState()に関してですが、これは関数コンポーネントでState(状態)を保持できるようにした機能です。今回はクリックしたという動作に合わせてStateが変化していくのでコンテナにStateを持たせています。 useState これでBadボタンの動きまで作成できました。GoodボタンもベースとなるRateButtonは同じでStateの動きが異なるだけなので同様に作成します。 GoodButtonContainer.tsx import React, { FC, useState } from "react"; import { RateButton } from "./RateButton"; type GoodButtonContainerProps = { buttonText: string; }; export const GoodButtonContainer: FC<GoodButtonContainerProps> = (props) => { const [goodNumber, setGoodNumber] = useState<number>(0); const addGoodNumber = () => { setGoodNumber((preState) => preState + 1); }; return ( <RateButton {...props} clickedNumber={goodNumber} onClick={addGoodNumber} /> ); }; あとはApp.tsxを以下のように修正します。 App.tsx import React from 'react'; import { BadButtonContainer } from "./BadButtonContainer"; import { GoodButtonContainer } from "./GoodButtonContainer"; export default function App() { return ( <> <GoodButtonContainer buttonText="good?" /> <BadButtonContainer buttonText="bad?" /> </> ); } これで完成です。 まとめ この記事ではコンポーネントのみを対象に説明しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React Testing Library】getBy, queryBy, findByの使い分け

0. 背景 ReactでTesting Libraryを用いたテストコードを書いているときに、特定クエリに一致する要素を取得する方法として、getBy..., queryBy..., findBy...の3パターンある事に気がつきました。 3つの使い分け方を簡単に調べたので備忘録として残しておきます。 参考にしたページはTesting Libraryの公式ページとなっております。 1. それぞれの説明 ※参照元: https://testing-library.com/docs/queries/about/ getBy getBy...: Returns the matching node for a query, and throw a descriptive error if no elements match or if more than one match is found (use getAllBy instead if more than one element is expected). getBy...: クエリにマッチするノードを返します。マッチする要素がない場合や、2つ以上のマッチが見つかった場合は、説明的なエラーを投げます。(Translated by DeepL) queryBy queryBy...: Returns the matching node for a query, and return null if no elements match. This is useful for asserting an element that is not present. Throws an error if more than one match is found (use queryAllBy instead if this is OK). queryBy...: クエリに一致するノードを返し、一致する要素がない場合は null を返します。これは、存在しない要素をアサートする場合に便利です。複数のマッチが見つかった場合は、エラーをスローします。(Translated by DeepL) findBy findBy...: Returns a Promise which resolves when an element is found which matches the given query. The promise is rejected if no element is found or if more than one element is found after a default timeout of 1000ms. findBy...: 指定されたクエリにマッチする要素が見つかったときに解決する Promise を返します。要素が見つからない場合や、デフォルトのタイムアウト(1000ms)後に複数の要素が見つかった場合には、Promiseは拒否されます。(Translated by DeepL) 2. 実際の使い方 以下のような使い分けにすれば良いのではないでしょうか? getBy: 特定クエリに一致する要素を取得する時はこちらを使う queryBy: 特定クエリに一致する要素がないことを取得する時はこちらを使う findBy: 特定クエリに一致する要素を非同期で取得する時はこちらを使う getBy: 一致する要素を取得 import { render, screen } from '@testing-library/react' import '@testing-library/jest-dom/extend-expect' import Home from '../Home' it('Should render hello text by getBy...', () => { render(<Home />) expect(screen.getByText('Hello by getBy!!')).toBeInTheDocument() }) queryBy: 一致する要素がないことを取得する import { render, screen } from '@testing-library/react' import '@testing-library/jest-dom/extend-expect' import Home from '../Home' it('Should NOT render hello text by queryBy...', () => { render(<Home />) expect(screen.queryByText('Hello by queryBy!!')).toBeNull() }) findBy: 一致する要素を非同期で取得する import { render, screen } from '@testing-library/react' import '@testing-library/jest-dom/extend-expect' import Home from '../Home' it('Should render hello text by findBy...', async () => { render(<Home />) expect(await screen.findByText('Hello by findBy!!')).toBeInTheDocument() }) 3. 最後に それではみなさん素敵な(笑)テストライフを!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cannot find module '@emotion/styled' from 'node_modules/@material-ui/styled-engine/node/index.js'のエラーの解決策

@emotion/styledのError 以下のようなErrorが出たので解決策をメモがわりに記載します。 Cannot find module '@emotion/styled' from 'node_modules/@material-ui/styled-engine/node/index.js' 解決策 npm install @emotion/react @emotion/styled yarnを入れている人なら yarn add @emotion/react @emotion/styled 該当部のpackage.jsonは以下になります。 "peerDependencies": { "@emotion/react": "^11.0.0", "@emotion/styled": "^11.0.0", "react": "^17.0.0" }, 多分、受講でこのようなErrorは指定のバージョンでやれば出ないと思いますが、 私は最新版のバージョンでやろうとしたため出たものだと思われます。 Module not found: Can't resolve '@emotion/react' のErrorであれば 以下のstack overflowさんの記事が参考になると思います。 https://stackoverflow.com/questions/65486256/module-not-found-cant-resolve-emotion-react
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Pages で最小構成のreactのhelloworldをデプロイしてみた

はじめに 前回の記事[1]でwsl2でreact環境を構築してみましたが、ポートフォリオを作るためには公開しなければいけません。 ポートフォリオの公開のためにサーバー関係をいろいろやっていると時間がとられるのでGitHub Pagesで公開することにしました。また、create-react-appコマンドで生成されたプロジェクトディレクトリの構成がよく分からないのでいらないものは削除して本当にhelloWorldのみを出力するディレクトリ構成にしました。 wslでやってますが、linux、macでも可能だと思います。 環境 windows10Home wsl2 Ubuntu 20.04LTS nodebrew nodejs 14.17.0 yarn 1.22.5 デプロイ とりあえずデプロイしてからいろいろ考えようと思います。 こちらのサイト[2][3][4]を参考にしました。 もともとGitHub Pagesのリポジトリは作っていたのでそれを使います。 分からない人は先ほどあげたサイトにも載っていますし、調べれば出てくるのでそちらを参照してください。 今回の記事でのGitHub Pagesのリポジトリの名前はreact_portfolioとします。 前回の記事で作成したプロジェクトディレクトリの中身をごっそりreact_portfolioに移動します。 とりあえずpushします。 今までの地獄のような環境構築の経験からyarnとnpmっていう2つのパッケージマネージャー混ぜない方がいいんじゃないかと思い調べたところ、一応混ぜない方が良さそうです[5]。 傾向としてもyarnを使っていこうみたいな流れがある気がするので本記事ではyarnを使っていきます。 なんかよく分からんけど必要らしいものをダウンロードします。 yarn add --dev gh-pages 参考サイトを参考にpackage.jsonにhomepageとdeploy、predeployを追加、ついでに名前も変更しておきました。 当然homepageのgithubのところは自分のに変えてください。 "devDependencies"の部分は上のコマンドしたら勝手に追加されたと思います。 正直このファイル自体よく分かっていないのですが依存関係なども管理しているっぽいです。 あんまり気にしすぎると本末転倒なのでポートフォリオ完成してから理解することにします。 あと参考サイトではnpmでビルドしているのをyarnでしています。 たぶん変えなくても大丈夫ですが個人的にこういうのめちゃくちゃ気になるので変えてます。 { "homepage": "https://it-tsumugi.github.io/react_portfolio", "name": "react_portfolio", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", "web-vitals": "^1.0.1" }, "scripts": { "predeploy": "yarn build", "deploy": "gh-pages -d build", "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "gh-pages": "^3.2.0" } } デプロイします もしかしたらリモートリポジトリを追加する際の名前をorigin以外にしているとエラー出るかもしれないです。 yarn deploy このコマンドだけで勝手にデプロイされます。 なんて便利!無宗教ですがyarn教に入信しそうです。 ただこのままだと反映されません。 githubのリポジトリのsettingのpagesでsourceをgh-pagesにしましょう。 ディレクトリはdocsにしてルートにindex.htmlが無くてもいいように出来るらしいですがrootでいいです。 これで反映されているはずなのでGitHub PagesにあるURLにアクセスしましょう。 GitHub Pagesは反映がかなり遅いのでもともと何か入れていた場合は数分かかるかもしれません。 数分待っても反映されない場合は何か間違っているかもしれません。 僕はhomepageのところの最後に間違えて「/」をいれていたせいで1時間くらいもがいてました。 とりあえずあのマークが表示されたらデプロイには成功しています。 余計なファイルを消す とりあえずデプロイには成功しました。 しかし、余計なものが多すぎます。 なんでこのマークぐるぐるしてるのか意味が分かりません。 無駄なものがあると思考がぐちゃぐちゃして訳が分からなくなるのでいらないものは消しましょう。 このサイト[6]を参考にしました。 publicとsrcはこのサイト通りにしましたが、yarn.lockとREADME.mdは残しておきました。 yarn.lockは依存関係的なのに影響しそうなのとREADME.mdはあとでどうせ作ろうと思っていたので。 まあそこらへんは気分ですね。 App.jsとindex.jsも参考サイト通り変えましょう。 変更がすべて終わったらpushしてdeployします。 例によって更新に数分かかります。 数分後に確認したらhelloworldが出力されているはずです。 その後他の文字に変えて更新してみて遊んでみてもいいです。 数分かかるけど。 検証 pushしないと変わらないのかなあと思っていたのですが、一回した後はdeployだけでページは更新されるみたいです。 たぶん普通のことなんだと思うんですが個人的にはなんかワクワクしますね! ローカルでプログラムしてデプロイして動作確認みたいな感じになるんでしょうか。 おわりに 今回はGitHub Pagesでreactのhelloworldをデプロイして、最小構成にしました。 本当はdocker、docker-compose、kubernetes、circleciとかで環境構築、デプロイとかも楽にするんでしょうね。 ちょっと首をつっこんでみたのですが沼りかけたのでおとなしくリリースするまではやめとくことにしました。 reactとデプロイ周りは前提知識、必要なツールが多すぎてリサーチと理解に割と時間かかりました。 デプロイ出来たのはちょっと感動です。 とりあえずこの最小構成からスタートしてどういう風にポートフォリオを作成するか考えていきたいと思います。 それではまた。 参考文献 [1]:【Mac難民】WSL2でのreactの環境構築 [2]:ReactのアプリをGithub pagesにデプロイしようとしたのにできなかった時の話と解決策 [3]:github pagesにreactアプリをデプロイして少しハマった話 [4]:Github PagesでReactアプリケーションをデプロイ [5]:[npm & Bower] Yarn 入門: npm との違いを探る [6]:Create React App で生成される React アプリを最小構成にする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む