PUROGU LADESU

ポエムがメインのブログです。

React フック

フック

関数コンポーネントに機能を追加するための仕組み

副作用フック

コンポーネントを描画、破棄するタイミングで何らかの処理を実行させる
フックは必ず関数コンポーネントのトップレベルで呼び出すこと。
ループ、条件分岐、入れ子関数では機能しません。

useEffect 初期描画時、再描画時(変数更新時)

useEffectの中で値を更新すると再描画されるので無限ループになってしまうので注意

const t = setInterval(() => {
  // タイマー設定時のcountを保持してしまい動かない
  // setCount(count + 1);
  setCount((c) => c + 1);

ターゲットになる変数を引数で指定すると、その変数の更新時のみ発動する。
第2引数がない場合、すべての変数更新時に発動する。
[]空配列を指定すると、更新時はなにもせず初回だけ発動する。

useEffect(() => {
  console.log("クリック")
  return () => {
    アンマウント時
  }
}, [count]);
useReducer

stateと更新処理を一箇所にまとめる。
単純な更新ならuseStateで十分なので、複雑な更新の場合に利用する。

引数としてstate, actionを受け取る
dispatchで指定するactionのタイプによって処理が変わる
更新したstateを返す

const [state, dispatch] = useReducer(
  (state, action) => {
    // action.typeによるswitch処理でstateを更新
    // stateを返す
  },
  {stateのデフォルト値}
)

dispatchによりstateを更新する。関数でラップしてコンポーネントから利用する。
dispatch({ type: "PLUS", amount: 1 });
useReducerでactionのtypeに応じてstate更新がなされる

コンテキスト

親子コンポーネントでの情報伝達のバケツリレーを解消する
上位コンポーネントで用意された値(Provide)を、下位コンポーネントで参照(Consume)。
stateをグローバルにした感じ。

コンテキストを提供するコンポーネントをProviderという
useContext経由でコンテキスト取得するコンポーネントをConsumerという

createContextして、valueに値をセットする

export const MyAppContext = createContext();
<MyAppContext.Provider value={c}>

Providerを入れ子にすれば複数利用できる

exportしたcreateContextを配下のコンポーネントで取り出す

const [count, setCount] = useContext(MyAppContext);
コンポーネントとコンテキストの分離

コンテキストにはコンテンツは設置せず、useStateとprops.childrenを置く
トップレベコンポーネントにはproviderを設置。
配下のコンポーネントではcontextを取得。

コンポーネントのキャッシング

コンテキストの配下に無いものが更新されても、コンテキストに依存するコンポーネントが再描画されてしまう。
useMemoを使いキャッシングする。依存する変数を指定する。

カスタムフック

再利用可能なロジックを切り出し、コンポーネントから呼び出して使う。

名前はuseXXXXとする
戻り地はstateや定義した関数など。

React ルーティング

ルーティング

URLに応じて処理を渡す先を変える
SPAではページ遷移もアプリが担う

インストール
npm install react-router-dom
基本

SwitchからRouteになりました。

Routeを入れ子にして階層構造を作る。
子ルートは親ルートのパスに連結して定義される。
親ルートに子ルートの中身を表示するにはOutletを使う
トップに表示する子ルートはpathではなくindexで表す
v6からはexact, endがなくても完全一致になった。

import {
  createBrowserRouter,
  createRoutesFromElements,
  RouterProvider,
  Route,
  NavLink, Link, Outlet,
  useNavigate
} from "react-router-dom";

<Route path="/" element={<App />}>
  <Route index element={<MyTop />} />
  <Route path="hello" element={<MyHello />} />
  <Route path="article/:id" element={<MyArticle />} />
  <Route path="*" element={<NotFound />} />
</Route>
<NavLink className={isCurrent} to="/">
タグ属性の分解代入

isActive属性がある場合に、クラスを追加

function isCurrent(link) {
  // タグから属性にアクセス
  return link.isActive ? "current" : undefined;
}
function isCurrent({ isActive }) {
  // 属性に直接アクセス
  return isActive ? "current" : undefined;
}
リンク

NavLink, Linkタグでリンク作成可能

画面遷移

useNavigateでプログラムから画面遷移が可能
navigate("/");

ルートパラメータ
<Route path="article/:id" element={<MyArticle />} />

useParamsを使う。
const params = useParams()
params.idでアクセス

指定より後ろのパスを取得
<Route path="search/*" element={<MySearch />} />

useParamsを使う。
params["*"]でアクセス

クエリ文字列を取得
<Route path="query" element={<MyQueryArticle />} />

useSearchParamsを使う
params.get("id")でアクセス

エラー時に表示する画面
<Route path="article/:id" errorElement={<MyError />} />

errorElementに指定
const error = useRouteError(); を使う
error.messageでアクセス
共通エラーはルートのAppに定義しても良い

ローダー

コンポーネントで使うデータの準備をするための関数
コンポーネントとデータ取得のコードを分離できる

1.リクエスト情報を受け取る
2.結果をPromiseで返す

データの取得はRouteタグのローダー関数でやってしまい、
useLoaderDataでその戻り値を取得して表示

action

サブミット処理をFormに書かずにRouteのaction属性に記載する

1.引数としてリクエスト情報を受け取る
2.戻り値として結果を返す

action属性にuseActionDataでアクションからの戻り地を取得
例)エラーチェックをしてエラー箇所を表示数する

Form

formではなくForm
フォームデータをrequestから取得
const form = await request.formData();
form.get("title");

React フォーム

フォーム

  • 制御コンポーネント Controlled Component useStateを使い、stateで値を保持する name属性とstateプロパティの名前を一致させる 値はvalueに設定する。
const [form, setForm] = useState({email:"xx@xx"})
<input name="email" value={form.email} />

算出プロパティ名。変数を[]で囲うとプロパティ名として使える
setForm(
  { ...form, [e.target.name]: e.target.value }
)
  • 非制御コンポーネント Uncontrolled Component stateで保持せず、使う際に取得する useRefは必ずnullにする。値を入れると変更できなくなる。 値はrefに設定する。 初期値はvalue,checked要素は使わない。defaultValue,defaultCheckedを使う。
const email = useRef(null);
<input name="email" ref={email} defaultValue="xx@xx"/>
email.current.value で取得。
テキストエリア <textarea value={form.memo} />
選択 <select value={form.fruits} />
選択複数 <select multiple={true} value={配列で渡す} /> e.target.optionsから取得
ラジオ <input type="radio" checked={form.sex === "male"} value="male" />
チェック <input type="checkbox" checked={form.send} />
チェック複数 <input type="checkbox" checked={form.cars.includes("toyota")} value="toyota" /> includesでデータにあったらチェック
ファイル <input type="file" > 
const file = useRefを使い、file.current.files[0]で取得

React 状態管理

state

  • 基本
    Props:コンポーネントに値を渡すためのもの。読み取り専用で変更不可
    State:状態管理のためのもの。変更可能。フォームの入力など。

  • 使い方
    関数コンポーネントではthisではなくuseStateを使う。
    useStateを使い、変数、更新関数、初期値を設定する

import { useState } from React
const [count, setCount] = useState(0)
親のstateを更新するメソッドを定義して子に渡す(ポイント)
<Child onUpdate={update}>
子のpropsから親のメソッドを呼んで、更新内容を渡す
props.onUpdate(1)

React 分岐条件、繰り返し、イベント処理

分岐条件と繰り返し

{articles.map((article) => 
  return <MyArticle {...article} key={article.url}/>
)}
  • key
    リストなどはタグにkeyをつけることで更新、追加の判別が可能となり、無駄な処理がなくなる。 keyはユニークであれば何でも良い。

  • 分岐
    ?: 3項演算子
    && trueの場合だけ表示
    {}の中で即時関数でifも使えるが、複雑な場合は無理せず、関数やコンポーネントにする

イベント処理

  • onEvent
    jsとは違いJXSではcamelCaseで書く。
    onClick onChange onFocus onKeyUp など
<MyEvent onChange={this.show.bind(this)} />
  • イベントオブジェクト
    生のjavascriptとは似ているが異なる。(SynteticEvent)
    イベントハンドラの引数eなどでアクセス。
    e.target 発生した要素
    e.type 種類
    e.preventDeafult()
    生のイベントオブジェクトは、e.nativeEventでアクセスする

  • 独自データ属性
    タグにdata-xxxという名前の属性を付与すると、e.target.datasest.xxxでアクセスできる。 属性によってでイベントを場合分けしたい場合など

React コンポーネント

コンポーネント

関数コンポーネントとクラスコンポーネントがある
hooksができたので関数コンポーネントがおすすめ

  • 関数コンポーネント
    returnでReact要素を返す
    propsを引数で受け取る

  • クラスコンポーネント
    Componentクラスを継承
    renderでReact要素を返す
    propsはthisでアクセス
    stateが使える
    ライフサイクルメソッドが使える

  • パラメータを渡す
    タグの属性値として指定する {}で数値や配列、オブジェクト、関数なども渡せる スプレッド構文...でオブジェクトを各属性に展開して渡せる

<Hello text="aaa" />
<Hello number={ 123 } />
<Hello { ...attrs } />
function MyHello(props) {
let word = props.text
<Hello>bbb</Hello>
  • 子要素を受け取る
let name = props.children  

文字列だけでなく、React要素でもOK

React 概要

環境構築

  • 雛形を作る(webpackも入る)
npx create-react-app xxx
npm start
  • npm run build 本番環境用にコンパイルしbuildに出力
  • npm run eject webpack/babelの設定情報をconfigに出力

  • React.StrictMode 非推奨の警告を出してくれる機能

  • JSX: タグをjavascriptの中に書ける
  • コンポーネント名は頭が大文字
  • Reactは変更されたDOMの部分のみ更新される(VirtualDOM)
  • VirautlDOMとは
    メモリ上に置かれたDOMのコピー。更新を最小限に抑える。

JSX

  • index.html内のdivタグなどをReactタグで置き換え
  • Javascriptの拡張言語で、タグを使用して記述。実行時にはJavascriptに変換される
  • JSXを使わないなら、React.createElementを使っても書ける
  • 唯一のルート要素を持つ
  • ルート要素を付けたくない場合ダミー要素
<React.Fragment> </React.Fragment>
または
<> ~ </>
このタグは出力されない。
class -> className
for -> htmlFor
tabindex -> tabIndex
  • htmlコメント構文は使えない
    <!-- コメント --> -> {/* コメント */}

  • テンプレートでjavascript式を埋め込む
    1 + 2 = { 1 + 2 } {}の中は自動でエスケープされる

  • 属性値の指定
    属性値でテンプレートを使う場合、クオートを付けない href="{url}" -> href={url}
    style属性はオブジェクトリテラル 'color: Red' -> {color: 'Red'}
    属性はオブジェクトリテラルでまとめられる {...attrs} attrs = {src: ".img", title: "img" }