Reactを学ぶ中で必ず押さえておきたいこと②
JavaScript
0. はじめに
Reactについて、勉強したことを備忘録として限定記事でまとめていたのですが、暇だったので公開記事にしました。
※2018年に書いた記事:Reactを学ぶ中で必ず押さえておきたいこと①
1. Reactとは
- UIコンポーネントを作成するためのライブラリことやな。
- Facebook社が開発しているから、期待値大やな。
- Reactを使うにあたり、仮想DOM、JSX、コンポーネント・・・といったワードが20000%の確率で出てくるんやな。
2. 仮想DOM
- そもそもDOMは、Document Object Modelの略やな。
- つまりは、HTMLにアクセスする窓口のことやな。
- DOMを直接更新する場合、DOMが変更されるたびにブラウザがHTMLを解析してレンダリングするから、コストが高いんやな。
- 仮想DOMでは、ページ変更前と変更後の仮想DOMを比較して、差分箇所を見つけて、リアルDOMに反映してくれるんやな。だからパフォーマンスが出るみたいやな。
3. JSX
- JavaScriptの拡張言語で、HTMLライクな記述ができるようになるんやな。
- 以下のイメージやな。
return (
React.createElement(
'button',
{className: 'info'},
onClick: test
'ぼたん');
);
return (
<button className="info" onClick={test}>ぼたん</button>
);
- 「JSだと」みたいに、
React.createElement
とか書いても、直感的じゃないから分かりにくいんやな。 - JSXは、結局はコンパイル時にReact要素(React.createElement)に変換される仕組みみたいやな。
{}
の中に変数を使えるんやな。- タグを階層構成で書く感じやな。
- ただ、最上位のタグは1つにせんとあかんから、
<>
で囲めばいいんやな。<div>
で囲ってもいいけど、HTMLで見たときに余計な<div>
タグが出てまうんやな。
return (
<>
<button>ぼたん1</button>
<button>ぼたん2</button>
</>
);
4. コンポーネント
- UIの部品のことやな。
- コンポーネントっていうのは、見た目だけでなく、機能(○○を更新とか)も含んでのことを言うんやな。
- 部品化することで、再利用しやすくなるんやな。オブジェクト指向みたいなもんやな。
- 1コンポーネント1ファイルで書くのがいいみたいやな。
- クラスコンポーネントと関数コンポーネントに分類できるんやな。
- 以下のイメージやな。
class Button extends React.Component {
render() {
return <button>...</button>
}
}
const Button = (props) => {
return <button>...</button>
}
- コンポーネントを組み合わせて画面を作っていくんやな。
- コンポーネントは親子関係にして作ってくんやな。親コンポーネント-子コンポーネントってことやな。
- 親コンポーネントから子コンポーネントにデータを受け渡すには、Propsっていう仕組みを使うんやな。
- Propsを使うことで、子コンポーネントで表示する値を変更できる(=固定にしなくていい)わけやな。
- Propsでは関数を渡したりもできるんやな。
例えば、ボタンクリックされたときに、子コンポーネントで値変更して、結果を親コンポーネントのstateを更新するときとかに使うんやな。
5. ライフサイクル
- ライフサイクルとは、コンポーネントが生成されてから破棄されるまでの期間のことやな。
- 以下のライフサイクルに分けられるみたいやな。シンプルやな。
- Mounting・・・コンポーネントが生成される期間。
- Updating・・・コンポーネントが変更される期間。
- Unmounting・・・コンポーネントが破棄される期間。
6. React Hooks
- React 16.8(2020年2月)からReactに追加された機能やな。
- これを使う事で、関数コンポーネントでもstateを扱うことが出来る様になったんやな。
- React Hooksは、基本フックとしてuseState・useEffect・useContextがあるみたいやな。
それ以外にも、useReducer・useCallback・useMemo・useRef・useImperativeHandle・useLayoutEffect・useDebugValueがあるみたいやな。
とりあえず基本フックのみ記載するかな。
6-1. useState
- 状態の定義や更新ができるんやな。
- つまり、コンポーネント内の値を書き換えたいときに使えるんやな。
- ちなみに、stateが変更されされたり、propsが変更されたときに、コンポーネントが再描画されるんやな。
- useStateのsetを呼びだす際は、prevStateを使うことで、更新前の値を使用できるんやな。
- useStateの使用方法は以下のイメージやな。
import { useState } from 'react'
export const Compornent = () => {
// state・・・現在の状態
// setState・・・更新関数
// 0・・・初期値
const[count, setCount] = useState(0);
const countUp = () => {
// こっちやと「今画面に出てる値+1」をする
// なので連打でボタン押下したとき等、カウントが合わなくなる可能性がある
// setCount(count + 1);
// こっちやと「変更前の値+1」してくれる
// 連打でボタン押下したときも問題ない
setCount(prev => prev + 1);
}
return (
<>
<input type="text" value={count}/>
<button onClick={countUp}>+</button>
</>
)
}
6-2. useEffect
- useEffectは、レンダリングのタイミングで呼び出される処理のことやな。
- レンダリングに関係ない処理って意味で、副作用って呼ばれてるみたいやな。
- レンダリング後に、apiを呼び出したり、DB処理をしたい場合とかによく使われるみたいやな。
- useEffectが呼び出されるタイミングってのは、制御できるんやな。
- useEffectの使用方法は以下のイメージやな。
import { CompornentB } from './CompornentB'
import { useState, useEffect } from 'react'
export const CompornentA = () => {
const[count, setCount] = useState(0);
const countUp = () => {
setCount(prev => prev + 1);
}
// 毎回のレンダリンで呼ばれる
useEffect(() => {
console.log("--- 毎回 ---")
console.log(count)
})
// 初回のレンダリングのみ呼ばれる
useEffect(() => {
console.log("--- 初回 ---")
console.log(count)
}, [])
// countが変更された場合のみ呼ばれる
useEffect(() => {
console.log("--- Count変更時 ---")
console.log(count)
}, [count])
// レンダリングされる前に呼ばれる
useEffect(() => {
return () => {
console.log("--- レンダリング前 ---")
console.log(count)
}
})
return (
<>
<input type="text" value={count}/>
<button onClick={countUp}>+</button>
</>
)
}
6-3. useContex
- Storeが簡単に作れるようになる仕組みやな。
- コンポーネント間でデータの受け渡しができるようになるんやけど、Propsみたいに「親から子へ」っていう制約がなくなるんやな。
- つまり、Storeを使うことで、親から孫へデータを受け渡しできたりするんやな。というか、アプリケーション全体で使いまわせるんやな。
- useContexの使用方法は以下のイメージやな。
import '../styles/globals.css'
import type { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<label>--- appです ---</label>
<br/>
<Component {...pageProps} />
</>
)
}
export default MyApp
import type { NextPage } from 'next'
import { CompornentA } from "./CompornentA"
import { TestContext } from "./store";
const Home: NextPage = () => {
return (
<TestContext.Provider value={{id : "123456"}}>
<label>--- indexです ---</label>
<br/>
<CompornentA/>
</TestContext.Provider>
)
}
export default Home
import { CompornentB } from './CompornentB'
export const CompornentA = () => {
return (
<>
<label>--- CompornentAです ---</label>
<br/>
<CompornentB/>
</>
)
}
import { useTestContext } from "./store";
export const CompornentB = () => {
const {id} = useTestContext();
return (
<>
<label>--- CompornentBです ---</label>
<br/>
<label>indexで設定した「{id}」を、CompornentBで表示しています</label>
</>
)
}
import { useContext, createContext, useState } from "react"
type ContextType = {
id: string
};
const testContext: ContextType = {
id: ""
};
export const TestContext = createContext(testContext);
export function useTestContext() {
return useContext(TestContext);
}