React習得のために、progate、やっすんのYouTube、公式チュートリアルをやってみましたが、まだ自力で実装できる気がしないと思い、こちらのとらゼミさんのYouTubeがわかりやすそうだったのでやってみました!
ちなみに、 やっすんのYouTube、公式チュートリアル は途中で挫折しています。
詳しい説明が無いので途中で何をやっているのかわからなくなり、自分にはダメでした…
今回こそはやりきって、実装に移りたいと思います!
とらゼミ動画を見て学んだことをまとめました。
Reactを使う理由
- 従来の、DOMを直接取得して変更を加える(再描画する)処理を行うとコストが高い。この問題をReactが解決してくれる。
- ビューの変更処理をブラウザでなくJavaScriptエンジンに任せることで、ブラウザの負荷を軽減する。
- 仮想DOMで差分のみ描画する。これにより必要な部分だけ書き換えることができる。
JSX
JSXとは、HTMLだけど、その中でJavaScriptが使えるイメージです。
なぜ使うのか
JavaScriptなので、最終的にはHTMLに変換されているが、JSXを使うことによってHTMLのように書くことができる。
使わない場合、React.createElementといった構文をいちいち書かないといけなくなる。
特殊な構文
JSXは必ず階層構造とする。
つまり、returnの下の階層に並列で存在してはならない。
そのため、divタグで囲います。
しかし、無意味なdivタグは使いたくないといった場合には、
<React.Fragment>といった書き方をし、これは省略して<>こう空タグで記述することもできる。
環境構築
create-react-appを使うことで、簡単にSPA シングルページアプリケーションを構築できます!
そのためには、以下のインストールが必要です。
- Homebrew
- nodebrew
- Node.js
- npm これはNode.jsをインストールすれば勝手にインストールされる。
それぞれどんな役割のものか?
Homebrew
mac OSのバージョン管理
nodebrew
nodeのバージョン管理
Node.js
サーバー環境で動くJavaScriptであり 、ローカル環境でJavaScriptを動かすために必要。
npm
Node.jsのパッケージマネージャー
バージョン管理をしてくれる。
全てのインストールができたら、いよいよReactに!
$ npx create-react-app react-tutorial-torazemi
npxとは?
ネットワーク上にあるnpxのコマンドを実行してくれます。
作成したディレクトリに移動
$ cd react-tutorial-torazemi
アプリの起動
$ npm start
これにより構築されたアプリはホットリロードに対応しています。
ホットリロードとは何か?
ファイルを編集したら、サーバーが自動で更新される。
コンポーネントはClassとFunctional(関数)があります。
しかし、Classは一昔前の記法で、今後はFunctionalを使いましょう!
昔はClassでないとできないことがあったが、React Hooksの登場で、ほぼ全てが、Functionalで使えるようになったためです。
であれば、記述量の少ないFunctionalを使った方がよいということです。
ClassとFunctionalの違い
ClassとFunctionalを比較します。以下は同じ挙動になります。
Class
import React, {Component} from 'react';
class Button extends Component {
render() {
return <button>Say, {this.props.hello}</button>
}
}
export default Button;
Functional
import React from 'react'; ←これは省略することも可能
const Button = (props) => {
return <button>Say, {props.hello}</button>
};
export default Button;
コンポーネント
Reactを使う上で必要な概念、コンポーネントについて見ていきます。
使う理由
- 同じ記述をせず、再利用するため、同じ役割はコンポーネントの呼び出しで実装する。
- 1コンポーネント = 1ファイルとすることで、読みやすくなる。
使い方
親と子に分かれて、子は呼び出される側になる。
子の側では、関数の定義とexportをする。
親の側では、importでの呼び出しと、JSX内で関数を呼び出す。
役割(責務)ごとにコンポーネントを分ける。
export, importの種類
default(名前無し)と名前付きがある。
default export
default exportではファイルごとexportします。
アロー関数と名前付き関数でのそれぞれの記法を見てみましょう!
アロー関数の場合
const Title = (props) => {
return <h2>{props.title}</h2>
};
export default Title;
名前付き関数の場合
export default function Title(props) {
return <h2>{props.title}</h2>
};
default exportしたコンポーネントは、一度1つのファイルにまとめられます。
このまとめられたところをエントリポイントといいます。
慣例的にエントリポイントはindex.jsで作るようになっている。
名前付きexport
export const addTax = (price) => {
return Math.floor(price * 1.1)
}
export const ...
1ファイル1コンポーネントでない場合に、関数単位でexportする場合に使用します。
名前付きimport
import {Content, Title} from "./index";
これにより、エントリポイントのindex.jsからContentとTitleコンポーネントがimportできる。
これを、まとめずに記述する場合、以下のようになる。
import Content from './Content'
import Title from './Title'
このように毎回、すべてのファイルで指定をしないといけないです。
defaultを使うと、一括でexport, importをすることができます。
Hooksとは何か
stateを関数コンポーネントでも使えるようにしたもの。
従来はclassコンポーネントでしか使うことができなかった。
stateをなぜ使うのか
要素の書き換えをするためにstateを使います。
JavaScriptの考えでいくとDOMで直接書き換えたくなります。
しかし、Reactでそれをやると、仮想DOMというReactのメリットを活かすことができないため、そのような処理はしてはいけないことになっています。
そこでstateを使用します。
Reactコンポーネントが再描画(レンダリング)するきっかけは?
stateかpropsが変更されたとき。
useStateの使い方
useStateによるstateの宣言
const [state, setState] = useState(initialState)
それぞれの役割
state: 現在の状態
setState: 現在の状態を更新するための関数
useState: これはReactのメソッド
initialState: 初期値
つまり、useStateが実行されると、現在の状態とそれを更新するための関数が返ってくるというわけです。
stateの更新
setState(newState)
setState: 更新関数
newState: 新しい値
setStateをnewStateに書き換える処理が走ります。
propsとstateの違い
props: 親から子のコンポーネントに引き渡す引数のようなもの
state: コンポーネントの中で宣言され、制御される
propsは親から子に渡されるだけで、子から親に対し値を更新することはできない。
stateをpropsに渡す
stateはコンポーネントの中でしか使えないため、propsに渡して更に子のコンポーネントに渡して使われる。
その際の更新関数は、そのままpropsとして渡さず、関数化する。
const Article = (props) => {
const [isPublished, setIsPublished] = useState(false)
const publishArticle = () => {
setIsPublished(true)
}
return (
<div>
<Title title={props.title} />
<Content content={props.content} />
<PublishButton isPublished={isPublished} onClick={publishArticle} />
</div>
);
};
isPublishedを子のコンポーネントの中のPublishButtonコンポーネントで処理する。
更新用関数setIsPublishedは、直接PublishButtonに渡すのでなく、publishArticleと関数化する。
この関数をPublishButtonのonClickというpropsとしてpublishArticleを渡している。
PublishButtonコンポーネントはこちら
const PublishButton = (props) => {
return (
<button onClick={() => props.onClick()}>
{props.isPublished.toString()}
</button>
)
}
propsとして受け取ります。
buttonタグでは、propsで渡ってきたonClickという関数がonClickイベントで実行される。
コールバック関数を使う場合の、関数の渡し方OK / NG例
OK
<PublishButton isPublished={isPublished} onClick={() => publishArticle()} />
NG
<PublishButton isPublished={isPublished} onClick={publishArticle()} />
こちらは、無限レンダリングが起きてしまう例です。
()を付けることによってpropsとして渡すときに関数を実行することになってしてしまう。
OKの例は、関数をpropsとして渡していますが、
NGの例は、レンダリングをするたびに関数を実行するという無限ループになってしまう。
useStateの実用的な使い方
const TextInput = () => {
const [name, setName] = useState('') setNameという更新関数が存在している。
const handleName = (event) => { setNameに値を渡すためのhandleNameという関数を宣言
setName(event.target.value) このhandleNameはeventをパラメータとして受け取る。
} event.target.valueはフォームの入力値
return (
<input
onChange={(event) => handleName(event)} だから、handleNameを使うときは引数の指定が必要。
type={'text'} onChangeイベントが発火したらeventという値をhandleNameという関数に渡す
value={name}
/>
);
};
つまり、onChangeベントでeventという値が変わる度に、handleNameがeventに渡され、event.target.valueがsetNameに渡される。
prevStateを活用する
クリックするとカウントアップしていくような機能に使える。
prevStateは、更新前の値を引数としてとってくることができる。
初期値を0として、関数countUpの中でsetCountを呼び出し、更新前の値に+1した値を返すというもの。
const Counter = () => {
const [count, setCount] = useState(0)
const countUp = () => {
setCount(prevState => prevState + 1)
}
countUp部を、returnを省略しないで書くと、以下のようになる。
const countUp = () => {
setCount(prevState => {
return prevState + 1
})
}
バグが出るcount機能の書き方
const countUp = () => {
setCount(count + 1)
}
この書き方の何がいけないのか?
クリック回数分正確にカウントがされない。クリック数とカウント数に差異が生じる。
prevStateは更新前の値を参照して、+1しているため、クリック数とカウント数に差異が生まれるということが無くなる。
ON/OFFを切り替えるボタン
true/falseを切り替えるようにする。
const ToggleButton = () => {
const [open, setOpen] = useState(false)
const toggle = () => {
setOpen(prevState => !prevState)
}
toggleという関数をつくり、setOpenのprevStateをtrue/falseを反転させて更新をかける。
!を付けることで反転ができる。
toggleというのは切り替えるという意味
useEffectを使う
useEffectとは・・・レンダリングにより引き起こされる処理のこと
実行タイミングの指定方法
毎回実行
useEffect(() => {
console.log("Current count is...", count)
})
初回レンダリング後のみ
useEffect(() => {
console.log("Current count is...", count)
}, [])
第二引数に空配列を指定する。
配列の中の値が変更されたときのみ実行されるというもの。
triggerが変更される度
useEffect(() => {
console.log("Current count is...", count)
}, [trigger])
trigger1かtrigger2が変更される度
useEffect(() => {
console.log("Current count is...", count)
}, [trigger1, trigger2])
useEffectをどう使うか
非同期通信をコンポーネントの中で使う場合は、useEffectの中で使うのがルール
fetch API というものがデフォルトで備わっている。
fetch・・・データを取りに行って取得して戻ってくるという意味。getとは違う。
このfetch APIを使って外部APIにアクセスできる。
クリーンアップ
クリーンアップとは、コンポーネントの中で外部DBやAPIを購読した場合の、購読の解除をすること。
購読とは、DBの値に変更があった場合などにそれを受け取り、それを基に表示を変えるなどの処理のこと。
なぜ解除をするか?値を取りっぱなしだと、意図しない挙動になってしまう。
if (open) {
console.log('Subscribe database...')
}
return () => {
console.log('Unsubscribe database!')
}
このreturnをクリーンアップ関数という
まとめ
全9回のYouTubeを全て最後まで理解することが出来ました。
“日本一わかりやすい”と命名されているだけあってめちゃめちゃ分かりやすかったです。
実際に手を動かしてアプリの作成はできないので、アプリを作成したくなりました!
それではアプリ制作に入っていこうと思います!!
コメント