20201120のReactに関する記事は13件です。

TypeError: Cannot assign to read only property 'jsx' of object '#<Object>'

【備忘録】

私自信TypeScriptに詳しくなかったのでこれでなぜ解決したかなど理由は分かりませんが、探すまで時間がかかったので、忘れないようにと残しておきます。

エラーまでにやったこと

$ npx create-react-app アプリ名 --template typescript
$ cd アプリ名
$ yarn start  <-  ここでエラー発生

エラー内容

$ yarn start
yarn start
yarn run v1.21.1
warning ../../../package.json: No license field
$ react-scripts start
アプリまでのパス/アプリ名/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:239
      appTsConfig.compilerOptions[option] = value;
                                          ^

TypeError: Cannot assign to read only property 'jsx' of object '#<Object>'
    at verifyTypeScriptSetup (/アプリまでのパス/アプリ名/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:239:43)
    at Object.<anonymous> (/アプリまでのパス/アプリ名/node_modules/react-scripts/scripts/start.js:31:1)
    at Module._compile (internal/modules/cjs/loader.js:1137:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

解決策(参考URLも載せます)

/アプリ名/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
変更前
238: } else if (parsedCompilerOptions[option] !== valueToCheck) {

変更後
238: } else if (parsedCompilerOptions[option] !== valueToCheck && option !== "jsx") {

こちらが参考URL
4.0.0 breaks with typescript (all versions) #9868

他の方で違う方法で解決されている記事もありましたので共有します
https://qiita.com/makishy/items/913e20dff7caf458c965

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【firebase authentication】永続化された認証情報の参照にAuth.currentUserは使ってはいけない

firebase.auth().currentUserとは

現在のユーザー認証情報を所持するプロパティです。

firebaseでは認証情報をクライアントに永続化が可能となっているので、永続化された認証情報が存在すれば

現在のユーザー認証情報

の対象となります。公式ドキュメント

リロードしようがブラウザ閉じようが認証状態は継続しているということですね、firebaseさまさまです。

本題

意気揚々Reactでこんなコードを書きます。

firebase.initializeApp({....})

const App = () => {
    retutn <Router>
        <LoginPage />
        <HogePage />
        <HugaPage />
    <Router />
}

if (firebase.auth().currentUser !== null) {
    console.log("前の認証情報が残っているよ!")
} else {
    console.log("認証情報は残っていないよ!")
}

ReactDOM.render(<App />, document.getElementById("root"))

実行してみましょう、LoginPageで何かしら認証を行いリロード!
ですが表示されるのは

認証情報は残っていないよ!

無慈悲.....

調査するところ認証情報の永続化はデフォルトでsessionモードと言われるものとなっており、今回の意図通りの挙動をしてくれる様子です。公式ドキュメント

もう少し調べると、認証し→リロード→HogePageを動かしている際にはcurrentUserが参照できる

ここから推測するにcurrentUserにデータが入ってくるのはfirebaseSDKのモジュールが生成されるタイミングではないようで少しラグがあるようのでは。。。。。?

ですがcurrentUserに入ってくるタイミングなんてものはもちろん検知できません。
そこでAuth.onAuthStateChangedを発見、signin,signoutが発生した際にコールバックを処理してくれるようです。
使えそうなので書き換えてみましょう。

const getStoredFirebaseAuthenticatedUser = () => 
    new Promise<firebase.User | null>(
        (resolve, reject) => firebase.auth().onAuthStateChanged(resolve, reject)
    );

firebase.initializeApp({....})

const App = () => {
    return <Router>
        <LoginPage />
        <HogePage />
        <HugaPage />
    <Router />
}

getStoredFirebaseAuthenticatedUser().then(user => {
    if (firebase.auth().currentUser !== null) {
        console.log("前の認証情報が残っているよ!")
    } else {
        console.log("認証情報は残っていないよ!")
    }
})

ReactDOM.render(<App />, document.getElementById("root"))

同じく、LoginPageで何かしら認証を行いリロードしてみます。

少し待ち

前の認証情報が残っているよ!

勝利!

まとめ

  • 永続化された認証情報の参照でcurrentUserを使うとnullになるケースがある
  • たぶんfirebaseSDKの初期化が終わってからcurrentUserに入るまでに時間がかかる
  • 初期化終了の検知はできないからOnChangeAuthStateでフックしてあげようね

(ならcurrentUserの定義() => Promsieにしろよ........)

ということでした、ハマったので皆さんお気をつけください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-react-app(typescript)が動かんくなった

突然create-react-app (typescript)で作成したプロジェクトが動作しなくなった模様

いつものようにプロジェクトを作成

npx create-react-app myapp --template typescript

作成したアプリを起動

cd myapp
yarn start

以下エラーが出る。なぜ?

/Users/hoge/react/myapp/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:239
      appTsConfig.compilerOptions[option] = value;
                                          ^

TypeError: Cannot assign to read only property 'jsx' of object '#<Object>'
    at verifyTypeScriptSetup (/Users/hoge/react/myapp/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js:239:43)
    at Object.<anonymous> (/Users/hoge/react/myapp/node_modules/react-scripts/scripts/start.js:31:1)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)
error Command failed with exit code 1.

解消方法

package.json変更

typescriptを^4.0.3から~4.0.3に変更

image.png

tsconfig.json変更

jsxをreact-jsxからreactに変更
image.png

あとは、yarn.lock削除してからyarn startを実行

とりあえず、これで解消しました。どうしたんだ一体。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSXとReact要素の定義を整理しました

JSXReact要素の定義についてざっくりと整理してみました。

JSXとは

JSXはReactでよく見るHTMLタグのようなもの。

<h1 className="greeting">Hello, world!</h1>

React要素とは

JSXから生成されるJavaScriptのオブジェクト。
Reactはこのオブジェクトを読み取りDOMを構築する。

上のJSXからはこのようなオブジェクトが生成される。

{
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
}

JSXからReact要素が生成される過程

  1. JSXはBabelによりReact.createElement()の呼び出しへとコンパイルされる。

  2. React.createElement()はオブジェクトを生成する。

このオブジェクトをReact要素と呼ぶ。
Reactはこのオブジェクトを読み取りDOMをレンダーする。

このようにJSXはコンパイル後にReact要素と呼ばれるJavaScriptのオブジェクトになるので、

  • 変数に代入したり、
  • 関数の返り値にしたり、
  • propsとして子コンポーネントに渡したり、

することができる。

最後に

とりあえずJSXReact要素は互いにコンパイル前後で呼び名が変わったもの、程度に理解しておけばよさそう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSXとReact要素について整理しました

JSXReact要素の定義についてざっくりと整理してみました。

JSXとは

JSXはReactでよく見るHTMLタグのようなもの。

<h1 className="greeting">Hello, world!</h1>

React要素とは

JSXから生成されるJavaScriptのオブジェクト。
Reactはこのオブジェクトを読み取りDOMを構築する。

上のJSXからはこのようなオブジェクトが生成される。

{
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
}

JSXからReact要素が生成される過程

  1. JSXはBabelによりReact.createElement()の呼び出しへとコンパイルされる。

  2. React.createElement()はオブジェクトを生成する。

このオブジェクトをReact要素と呼ぶ。
Reactはこのオブジェクトを読み取りDOMをレンダーする。

このようにJSXはコンパイル後にReact要素と呼ばれるJavaScriptのオブジェクトになるので、

  • 変数に代入したり、
  • 関数の返り値にしたり、
  • propsとして子コンポーネントに渡したり、

することができる。

最後に

とりあえずJSXReact要素は互いにコンパイル前後で呼び名が変わったもの、程度に理解しておけばよさそう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-hook-formの基本

久しぶりの投稿になります。今後は週一記事以上は書けるように頑張ります!今回はreact-hook-formについての記事です。公式ドキュメントの内容を、自分なりにまとめてみました。より詳しく知りたい方は公式ドキュメントも見てみて下さい!

参考:公式ドキュメント

react-hook-formとは

inputとかのformに関係するデータを使う時に、Stateを使わなくて良くて、レンダリング回数を減らせる!

インストール

## yarnの場合
yarn add react-hook-form

## npmの場合
npm install react-hook-form

以上!TypeScriptの型定義も含まれてます。

↓↓↓簡単な例

import React from 'react';
import { useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';

type FormInputs = {
  name: string;
  email: string;
};

export const Demo = () => {
  const { register, errors, handleSubmit, reset } = useForm<FormInputs>();

  const on_submit = (data: FormInputs) => {
    console.log(data);
    reset();
  };

  return (
    <form onSubmit={handleSubmit(on_submit)}>
      <input name="name" ref={register} />
      <input
        name="email"
        ref={register({
          required: true,
          maxLength: 60,
          pattern: {
            value: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
            message: 'メールアドレスの形式が不正です',
          },
        })}
      />
      <button type="submit">Submit</button>
      <ErrorMessage errors={errors} name="email" message={errors.email?.message} />
    </form>
  );
};

↓この例だと入力した値はこんな風に出力される。それぞれの機能を解説して行きます。

{name: 入力した値,email: 入力した値}

useForm

react-hook-formからインポートするものはいくつかあるが、ほとんどuseFormから取得することが多い。

const { register, reset, handleSubmit } = useForm({
  mode: onSubmit,
  defaultValues: {name: "aaa", email: test@test.com}
})

引数にオブジェクトで色んな設定みたいなのができる

mode 初回のバリデーションの実行タイミング
(初期値:onSubmit)
onChange or onBlur or onSubmit or onTouched or all
reValidateMode 初回のバリデーション実行後、次の実行タイミング
(初期値: onChange)
onChange or onBlur or onSubmit
defaultValues 初期値をオブジェクトで入力します
(resetでdefaultValuesの値に戻る)
{name属性の値: 初期値,...}
resolver 他のvalidationライブラリを使う時
shouldUnregister 入力要素がアンマウントされたら、値の参照を解除、falseなら入力された値を保持
(初期値: true)
true or false

register

inputなどに入力された値を参照するために使う。name属性を設定する必要があり、registerはrefに入れる。UIライブラリを使う場合はcontrol参照。一番使う。

↓nameの付け方によって、dataの形が変わる.

name="firstName" →{ firstName: 'value'}
name="firstName[0]" →{ firstName: [ 'value' ] }
name="name.firstName" →{ name: { firstName: 'value' } }
name="name.firstName[0]" →{ name: { firstName: [ 'value' ] } }

引数にオブジェクトで色んなバリデーションが設定できる.

required 必須項目にするか true or false or エラーメッセージ
maxLength 最大文字数 {value: number, message: エラーメッセージ}
minLenght 最小文字数 {value: number, message: エラーメッセージ}
max 最大データ量 {value: number, message: エラーメッセージ}
min 最小データ量 {value: number, message: エラーメッセージ}
pattern 文字の形式 {value: 正規表現, message: エラーメッセージ}
validate カスタム {任意の名前: value => booleanを返す式 or 関数 || エラーメッセージ}
<input
   name="email"
   ref={register({
   required: true,
   maxLength: 60,
   pattern: {
       value: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
       message: 'メールアドレスの形式が不正です',
      },
   })}
   validate: {
       lessThanTen: value => parseInt(value, 60) < 60 || '60文字以内で入力して下さい'
   }
/>

unregister

引数に入れたnameはregisterで参照しなくなる。配列を入れて、複数も可能。unregister(['name','email'])

<button onClick={() => unregister("email")}>email_unregister</button>

errors

registerなどで設定したバリデーションを通らなかった時にエラーのデータが入る。エラーメッセージを設定している場合は、それも取得できる。

<input name="name" ref={register({required: '入力して下さい'}) />
{errors.name && <p>errors.name.message</p>}

watch

第一引数入れたnameの値を監視。第二引数は初期値を設定可能。unregisterと同様に配列に入れて複数も可能。何も入れないと、全てのnameの値を取得。レンダリング回数は増える。

const watch_name = watch("name", false);
const watch_all_fields = watch();
const watch_fields = watch(["name", "email"]);

handleSubmit

ラップした関数にformのdataをオブジェクトの形で渡してくれる。on_submitの引数にdataがあるのはそのため。
event.preventDefalut()も必要なし。

const on_submit = (data: FormInputs) => {
    console.log(data);
};

return (
    <form onSubmit={handleSubmit(on_submit)}>
...

reset

formの中の状態を初期化する関数。defaultValueが設定されていたら、その値になる

const on_click =()=>{
  reset();
}

setError

第一引数に指定したnameにエラーをセットする関数。第二引数にtype(requiredやminLengthなど)とエラーメッセージをオブジェクトとしていれる。
typeを変えるとどう変わるかが、よく分からないので分かる方いたら教えて下さい!

<button onClick={() => setError("email", { type: "required", message: "" })}>

clearErrors

引数に入れたnameのerrorを消す関数。こちらも配列で複数指定できる。

<button onClick={() => clearErrors("name")}>

getValues

引数に入れたnameの現在の値を取得。こちらも配列に入れて複数、空なら全てのnameの値を取得。watchとの違いは常に監視せず、再レンダリングもされない。ボタンを押して時に取得するとかならこっちの方がパフォーマンス的に良さそう。

const values = getValues();
const single_value = getValues("name");
const multiple_values = getValues(["name", "email"]);

setValue

第一引数に入れたnameに第二引数に入れた値をセットする関数。その際にshouldValidateでバリデーションを実行するかどうか、shouldDirtyで変更後に変更の有無の判定を行うかどうか

<button onClick={()=> setValue('name', 'value', { shouldValidate: true, shouldDirty: true })}>

trigger

引数に入れたnameのバリデーションを実行する関数。こちらも配列で複数、空なら全体。

<button type="button" onClick={() => { trigger("lastName") }}>Trigger</button>

control

Controllerのnameの値を参照するのに使う。バリデーションはできない。useWatchuseFieldArrayにも使う。

<Controller
  as={<TextInput />}
  control={control}
  name="name"
/>

formState

form内の入力の有無や送信の状態などを取得できる。formState.isSubmittingはbuttonにローディングをつける時によく使う。

isDirty 全体で何かしら変更があったらtrueになる true or false
dirtyFields それぞれの入力要素で何かしらの変更があったらtrue {name属性の値: true or false,...}
touched それぞれの入力要素で何かしらの操作をしたらtrueになる
(フォーカスするだけでも、onBlurのタイミングで反映される)
{name属性の値: true or false,...}
isSubmitted formが送信されたらtrue、resetでfalseに戻る true or false
isSubmitSuccessful formの送信が成功したらtrue true or false
isSubmitting formの送信中にtrue true or false
submitCount formの送信された回数 number
isValid 何かしらエラーがあったらtrue
(modeがonChange or onBlurの時のみ)
true or false
errors バリデーションのエラーのオブジェクトが入る {name属性の値: {
type: "required",
message: "",
ref: <input name="name属性の値" type="text">,
},...}
import React from "react";
import { useForm } from "react-hook-form";

export const Demo = () => {
  const { register, handleSubmit, errors, formState } = useForm();
  const on_submit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="name" ref={register} />
      {isDirty && <p>Form is dirty.</p>}
      {isSubmitting && <span>Submitting...</span>}
      <button type="submit" />
    </form>
  );
}

Controller

UIライブラリを使う時に使用。registerだと参照できないことが多い。(MaterialUIのTextFieldとかはinputRefregisterを入れて参照できる)。ruleregisterの中に書く感じでバリデーションを書ける。defaultValueも設定可能
asの中に全部入れちゃうのが簡単

<Controller
  as={<TextInput />}
  control={control}
  name="name"
  rules={{required: true}}
  defaultValue="aaa"
/>

<Controller
  control={control}
  name="email"
  render={({ onChange, onBlur, value, name, ref }) => (
    <TextField
      onBlur={onBlur}
      onChange={onChange}
      checked={value}
      inputRef={ref}
    />
  )}
/>

ErrorMessage

指定したnameのエラーメッセージを表示できる。messageはstringならOK

<ErrorMessage errors={errors} name="email" message={errors.email?.message} />

useFormContext,FormProvider

FormProvideruseFormregistererrorsなどをまとめて渡して、ラップされたコンポーネントでuseFormContextを使うと、その渡された値を使うことができる。

import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";

export const Demo = () => {
  const methods = useForm();
  const on_submit = data => console.log(data);

  return (
    <FormProvider {...methods} >
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        <Input />
        <button type="submit" />
      </form>
    </FormProvider>
  );
}

const Input = () => {
  const { register } = useFormContext();
  return <input name="name" ref={register} />;
}

useWatch

controlを渡すことでwatchを別のコンポーネントでも使えるようにした感じ。

import React from "react";
import { useForm, useWatch } from "react-hook-form";

const Watch = ({ control }) => {
  const name = useWatch({ control, name: 'name', defaultValue: 'aaa' });

  return <div>{name}</div>;
}

type FieldInputs = {
    name: string;
}

export const Demo = () => {
  const { register, control, handleSubmit } = useForm<FieldInputs>();

  return (
    <form onSubmit={handleSubmit(data => console.log("data", data))}>
      <input ref={register} name="name" />
      <Watch control={control} />
      <button type="submit" />
    </form>
  );
}

useFieldArray

下の写真みたいな感じで、同じinputなどを増減させたい時に使えます。公式ドキュメントから、YoutubeのuseFieldArryの紹介動画に飛べるので見るとわかりやすいです。

image.png

↓こんな感じでuseFormのように色んなメソッドを使えます。nameとcontrolが必要です。defaultValueはuseFormで設定できます。

const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
    control,
    name: "demo"
});

↓3列目は例です。

fields mapを使ったりして、入力要素をレンダリングするのに使用。idやdefaultValueが入ったオブジェクト
append fieldsの最後にinputを追加 append({name: "aaa"})
prepend fieldsの先頭にinputを追加 prepend({name: "aaa"})
insert fieldsの特定の位置にinputを追加 insert(3,{name: "aaa"})
swap inputの位置を入れ替える swap(1,2)
move inputの位置を動かす move(1,2)
remove 特定のinputを削除、引数無しで全削除 remove(1) remove()
import React from 'react';
import { useForm, useFieldArray } from 'react-hook-form';

export const Demo = () => {
  const { register, control, handleSubmit } = useForm({
    defaultValues: {
      demo: [{ name: 'name', email: 'email@email.com' }],
    },
  });
  const { fields, append, prepend, remove } = useFieldArray({
    control,
    name: 'demo',
  });

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      {fields.map((item, index) => (
        <div key={item.id}>
          <input
            name={`demo[${index}].name`}
            ref={register}
            defaultValue={item.name}
          />
          <input
            name={`demo[${index}].email`}
            ref={register}
            defaultValue={item.email}
          />
          <button type="button" onClick={() => remove(index)}>
            Delete
          </button>
        </div>
      ))}
      <button
        type="button"
        onClick={() =>
          append({ name: 'appendName', email: 'append@email.com' })
        }
      >
        append
      </button>
      <button
        type="button"
        onClick={() =>
          prepend({
            name: 'prependName',
            email: 'prepend@email.com',
          })
        }
      >
        prepend
      </button>
      <input type="submit" />
    </form>
  );
};


終わりに

ここまで読んでいただきありがとうございます!
少しでもreact-hook-formの理解が深まれば幸いです。自分も書きながら、react-hook-formの便利さが機能が理解できました。
質問、感想、改善点などをコメントでいただけるとモチベーションにつながりますのでよければお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-hook-formの使い方を解説!

久しぶりの投稿になります。今後は週一記事以上は書けるように頑張ります!今回はreact-hook-formについての記事です。公式ドキュメントの内容を、自分なりにまとめてみました。より詳しく知りたい方は公式ドキュメントも見てみて下さい!

参考:公式ドキュメント

react-hook-formとは

inputとかのformに関係するデータを使う時に、Stateを使わなくて良くて、レンダリング回数を減らせる!

インストール

## yarnの場合
yarn add react-hook-form

## npmの場合
npm install react-hook-form

以上!TypeScriptの型定義も含まれてます。

↓↓↓簡単な例

import React from 'react';
import { useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';

type FormInputs = {
  name: string;
  email: string;
};

export const Demo = () => {
  const { register, errors, handleSubmit, reset } = useForm<FormInputs>();

  const on_submit = (data: FormInputs) => {
    console.log(data);
    reset();
  };

  return (
    <form onSubmit={handleSubmit(on_submit)}>
      <input name="name" ref={register} />
      <input
        name="email"
        ref={register({
          required: true,
          maxLength: 60,
          pattern: {
            value: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
            message: 'メールアドレスの形式が不正です',
          },
        })}
      />
      <button type="submit">Submit</button>
      <ErrorMessage errors={errors} name="email" message={errors.email?.message} />
    </form>
  );
};

↓この例だと入力した値はこんな風に出力される。それぞれの機能を解説して行きます。

{name: 入力した値,email: 入力した値}

useForm

react-hook-formからインポートするものはいくつかあるが、ほとんどuseFormから取得することが多い。

const { register, reset, handleSubmit } = useForm({
  mode: onSubmit,
  defaultValues: {name: "aaa", email: test@test.com}
})

引数にオブジェクトで色んな設定みたいなのができる

mode 初回のバリデーションの実行タイミング
(初期値:onSubmit)
onChange or onBlur or onSubmit or onTouched or all
reValidateMode 初回のバリデーション実行後、次の実行タイミング
(初期値: onChange)
onChange or onBlur or onSubmit
defaultValues 初期値をオブジェクトで入力します
(resetでdefaultValuesの値に戻る)
{name属性の値: 初期値,...}
resolver 他のvalidationライブラリを使う時
shouldUnregister 入力要素がアンマウントされたら、値の参照を解除、falseなら入力された値を保持
(初期値: true)
true or false

register

inputなどに入力された値を参照するために使う。name属性を設定する必要があり、registerはrefに入れる。UIライブラリを使う場合はcontrol参照。一番使う。

↓nameの付け方によって、dataの形が変わる.

name="firstName" →{ firstName: 'value'}
name="firstName[0]" →{ firstName: [ 'value' ] }
name="name.firstName" →{ name: { firstName: 'value' } }
name="name.firstName[0]" →{ name: { firstName: [ 'value' ] } }

引数にオブジェクトで色んなバリデーションが設定できる.

required 必須項目にするか true or false or エラーメッセージ
maxLength 最大文字数 {value: number, message: エラーメッセージ}
minLenght 最小文字数 {value: number, message: エラーメッセージ}
max 最大データ量 {value: number, message: エラーメッセージ}
min 最小データ量 {value: number, message: エラーメッセージ}
pattern 文字の形式 {value: 正規表現, message: エラーメッセージ}
validate カスタム {任意の名前: value => booleanを返す式 or 関数 || エラーメッセージ}
<input
   name="email"
   ref={register({
   required: true,
   maxLength: 60,
   pattern: {
       value: /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
       message: 'メールアドレスの形式が不正です',
      },
   })}
   validate: {
       lessThanTen: value => parseInt(value, 60) < 60 || '60文字以内で入力して下さい'
   }
/>

unregister

引数に入れたnameはregisterで参照しなくなる。配列を入れて、複数も可能。unregister(['name','email'])

<button onClick={() => unregister("email")}>email_unregister</button>

errors

registerなどで設定したバリデーションを通らなかった時にエラーのデータが入る。エラーメッセージを設定している場合は、それも取得できる。

<input name="name" ref={register({required: '入力して下さい'}) />
{errors.name && <p>errors.name.message</p>}

watch

第一引数入れたnameの値を監視。第二引数は初期値を設定可能。unregisterと同様に配列に入れて複数も可能。何も入れないと、全てのnameの値を取得。レンダリング回数は増える。

const watch_name = watch("name", false);
const watch_all_fields = watch();
const watch_fields = watch(["name", "email"]);

handleSubmit

ラップした関数にformのdataをオブジェクトの形で渡してくれる。on_submitの引数にdataがあるのはそのため。
event.preventDefalut()も必要なし。

const on_submit = (data: FormInputs) => {
    console.log(data);
};

return (
    <form onSubmit={handleSubmit(on_submit)}>
...

reset

formの中の状態を初期化する関数。defaultValueが設定されていたら、その値になる

const on_click =()=>{
  reset();
}

setError

第一引数に指定したnameにエラーをセットする関数。第二引数にtype(requiredやminLengthなど)とエラーメッセージをオブジェクトとしていれる。
typeを変えるとどう変わるかが、よく分からないので分かる方いたら教えて下さい!

<button onClick={() => setError("email", { type: "required", message: "" })}>

clearErrors

引数に入れたnameのerrorを消す関数。こちらも配列で複数指定できる。

<button onClick={() => clearErrors("name")}>

getValues

引数に入れたnameの現在の値を取得。こちらも配列に入れて複数、空なら全てのnameの値を取得。watchとの違いは常に監視せず、再レンダリングもされない。ボタンを押して時に取得するとかならこっちの方がパフォーマンス的に良さそう。

const values = getValues();
const single_value = getValues("name");
const multiple_values = getValues(["name", "email"]);

setValue

第一引数に入れたnameに第二引数に入れた値をセットする関数。その際にshouldValidateでバリデーションを実行するかどうか、shouldDirtyで変更後に変更の有無の判定を行うかどうか

<button onClick={()=> setValue('name', 'value', { shouldValidate: true, shouldDirty: true })}>

trigger

引数に入れたnameのバリデーションを実行する関数。こちらも配列で複数、空なら全体。

<button type="button" onClick={() => { trigger("lastName") }}>Trigger</button>

control

Controllerのnameの値を参照するのに使う。バリデーションはできない。useWatchuseFieldArrayにも使う。

<Controller
  as={<TextInput />}
  control={control}
  name="name"
/>

formState

form内の入力の有無や送信の状態などを取得できる。formState.isSubmittingはbuttonにローディングをつける時によく使う。

isDirty 全体で何かしら変更があったらtrueになる true or false
dirtyFields それぞれの入力要素で何かしらの変更があったらtrue {name属性の値: true or false,...}
touched それぞれの入力要素で何かしらの操作をしたらtrueになる
(フォーカスするだけでも、onBlurのタイミングで反映される)
{name属性の値: true or false,...}
isSubmitted formが送信されたらtrue、resetでfalseに戻る true or false
isSubmitSuccessful formの送信が成功したらtrue true or false
isSubmitting formの送信中にtrue true or false
submitCount formの送信された回数 number
isValid 何かしらエラーがあったらtrue
(modeがonChange or onBlurの時のみ)
true or false
errors バリデーションのエラーのオブジェクトが入る {name属性の値: {
type: "required",
message: "",
ref: <input name="name属性の値" type="text">,
},...}
import React from "react";
import { useForm } from "react-hook-form";

export const Demo = () => {
  const { register, handleSubmit, errors, formState } = useForm();
  const on_submit = data => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="name" ref={register} />
      {isDirty && <p>Form is dirty.</p>}
      {isSubmitting && <span>Submitting...</span>}
      <button type="submit" />
    </form>
  );
}

Controller

UIライブラリを使う時に使用。registerだと参照できないことが多い。(MaterialUIのTextFieldとかはinputRefregisterを入れて参照できる)。ruleregisterの中に書く感じでバリデーションを書ける。defaultValueも設定可能
asの中に全部入れちゃうのが簡単

<Controller
  as={<TextInput />}
  control={control}
  name="name"
  rules={{required: true}}
  defaultValue="aaa"
/>

<Controller
  control={control}
  name="email"
  render={({ onChange, onBlur, value, name, ref }) => (
    <TextField
      onBlur={onBlur}
      onChange={onChange}
      checked={value}
      inputRef={ref}
    />
  )}
/>

ErrorMessage

指定したnameのエラーメッセージを表示できる。messageはstringならOK

<ErrorMessage errors={errors} name="email" message={errors.email?.message} />

useFormContext,FormProvider

FormProvideruseFormregistererrorsなどをまとめて渡して、ラップされたコンポーネントでuseFormContextを使うと、その渡された値を使うことができる。

import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";

export const Demo = () => {
  const methods = useForm();
  const on_submit = data => console.log(data);

  return (
    <FormProvider {...methods} >
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        <Input />
        <button type="submit" />
      </form>
    </FormProvider>
  );
}

const Input = () => {
  const { register } = useFormContext();
  return <input name="name" ref={register} />;
}

useWatch

controlを渡すことでwatchを別のコンポーネントでも使えるようにした感じ。

import React from "react";
import { useForm, useWatch } from "react-hook-form";

const Watch = ({ control }) => {
  const name = useWatch({ control, name: 'name', defaultValue: 'aaa' });

  return <div>{name}</div>;
}

type FieldInputs = {
    name: string;
}

export const Demo = () => {
  const { register, control, handleSubmit } = useForm<FieldInputs>();

  return (
    <form onSubmit={handleSubmit(data => console.log("data", data))}>
      <input ref={register} name="name" />
      <Watch control={control} />
      <button type="submit" />
    </form>
  );
}

useFieldArray

下の写真みたいな感じで、同じinputなどを増減させたい時に使えます。公式ドキュメントから、YoutubeのuseFieldArryの紹介動画に飛べるので見るとわかりやすいです。

image.png

↓こんな感じでuseFormのように色んなメソッドを使えます。nameとcontrolが必要です。defaultValueはuseFormで設定できます。

const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
    control,
    name: "demo"
});

↓3列目は例です。

fields mapを使ったりして、入力要素をレンダリングするのに使用。idやdefaultValueが入ったオブジェクト
append fieldsの最後にinputを追加 append({name: "aaa"})
prepend fieldsの先頭にinputを追加 prepend({name: "aaa"})
insert fieldsの特定の位置にinputを追加 insert(3,{name: "aaa"})
swap inputの位置を入れ替える swap(1,2)
move inputの位置を動かす move(1,2)
remove 特定のinputを削除、引数無しで全削除 remove(1) remove()
import React from 'react';
import { useForm, useFieldArray } from 'react-hook-form';

export const Demo = () => {
  const { register, control, handleSubmit } = useForm({
    defaultValues: {
      demo: [{ name: 'name', email: 'email@email.com' }],
    },
  });
  const { fields, append, prepend, remove } = useFieldArray({
    control,
    name: 'demo',
  });

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      {fields.map((item, index) => (
        <div key={item.id}>
          <input
            name={`demo[${index}].name`}
            ref={register}
            defaultValue={item.name}
          />
          <input
            name={`demo[${index}].email`}
            ref={register}
            defaultValue={item.email}
          />
          <button type="button" onClick={() => remove(index)}>
            Delete
          </button>
        </div>
      ))}
      <button
        type="button"
        onClick={() =>
          append({ name: 'appendName', email: 'append@email.com' })
        }
      >
        append
      </button>
      <button
        type="button"
        onClick={() =>
          prepend({
            name: 'prependName',
            email: 'prepend@email.com',
          })
        }
      >
        prepend
      </button>
      <input type="submit" />
    </form>
  );
};


終わりに

ここまで読んでいただきありがとうございます!
少しでもreact-hook-formの理解が深まれば幸いです。自分も書きながら、react-hook-formの便利さが機能が理解できました。
質問、感想、改善点などをコメントでいただけるとモチベーションにつながりますのでよければお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】React Tableで行をクリックした際のonclickイベントハンドラを設定する方法

メモとして残します。

みんな大好き、React Tableですが、行をクリックした際のイベントハンドラの設定方法メモとして残します。

■やり方

下記の通りgetTdPropsプロパティに設定をします。

<ReactTable
    getTdProps={(state, rowInfo, column, instance) => {
        return {
            onClick: e => {
                //if(column.id !== 'col-check'){
                    // 基本的な処理
                //  return
                //}
            }
        }
    }}
/>

ちなみに、getTrPropsというプロパティもありますが、このプロパティだと、例外的にイベントを発火させたくない列があったときに対応できないため、getTrPropsはあえて、採用しませんでした。
他thといった要素にも設定できるため、公式で確認しましょう。
image.png

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ツンデレ湯婆婆はReactで色恋するのか?

あらすじ

みなさま、お腹いっぱいでしょうか?
「湯婆婆ネタはもういらない」と?
いまさら感が強いですが、またまた湯婆婆のラブコメと学ぶ入門記事です。

湯婆婆ブームもそろそろ落ち着いてきましたね。
Javaで湯婆婆を実装してみるが元ネタです。

難易度☆★★★★

書いたコードの難易度としては、
ProgateReactコース修了レベルです。
やはり湯婆婆は入門者のゲーミフィケーションに最適ですね。

相違点

Reactは既に「React (JavaScript) で湯婆婆を実装してみる」で紹介されています。
後発として差別化をします。

  • BabelではなくTypeScriptを使用
  • CodePen.ioで形成した湯婆婆を埋め込み
  • 書き終えた契約書はReactiveに瞬間移動し湯婆婆の手の中へ
  • 契約書はQiitaカラー#55c500にして統一感を演出

恋する乙女、ツンデレ湯婆婆ちゃん

See the Pen React-Yubaba by ShortArrow (@ShortArrow) on CodePen.

言語による冷静な事務対応の限界

2つの言語を試してみて、気が付いたことがあります。
どの時点まで?田さんに冷静に対応できるのか?
それが言語によって「簡単に調節できるか」が異なるのです。

以前書いた記事「Powershellで湯婆婆の召喚魔法を実装」では、
Powershellでした。

契約書だよ。そこに名前を書きな。
��田
フン。��というのかい。贅沢な名だねぇ。
今からお前の名前は��。いいかい、��よ。分かったら返事をするんだ、、�!�!!

この時の湯婆婆ちゃんは、
契約書に記載した?田という正式名すら発声できません。
それどころか視界不良に陥り、契約書が見えていないようです。
「デレデレ」過ぎてこっちが恥ずかしいですね。

ツンデレ湯婆婆ちゃん

今回の湯婆婆ちゃんは、Javascriptです。
?田さんという名前を発声することができました。

フン。?田というのかい。贅沢な名だねぇ。

ここまでは「ツン」ですね。
ところがその直後、自分で考えたニックネームを発声できません。

今からお前の名前は�だ。いいかい、�だよ。分かったら返事をするんだ、�!!

恥ずかしくて「デレ」ています。

「アオハルかよ」って感じですね。
挿絵として「少女漫画風の湯婆婆」が欲しいです。

添え字の境界値に気を付けよう

境界値に気を付けなければ、以下の等式が成り立つ恐れがあります。

1 ÷ (名前の長さ + 1) = 湯婆婆が絶句する確率

下記のhandleClick()は湯婆婆の名前を盗むロジックのコアです。
この中で、(this.state.name.length - 1)として配列の添え字の番号に合わせています。

handleClick() {
    const randamIndex = Math.round(Math.random() * (this.state.name.length - 1));
    const madeName = this.state.name.substring(randamIndex, randamIndex + 1);
    this.setState({
        clicked: true,
        handleName: madeName
    });
}

仮に、randamIndexの定義が、

const randamIndex = Math.round(Math.random() * this.state.name.length);

だとしましょう。

Math.random()で0~1の範囲を作り出しています。
その結果、名前が御成敗式目の場合にrandamIndexの値は0~5となります。
そうすると、randamIndexの値が0の時はmadeNameで、4の時はmadeNameです。

そうなんです。randamIndexが5になれば、madeNameの値はヌル文字列です。

やはり「マイナス1」って偉大な数字ですね。

冷静な事務対応を執行するには

湯婆婆ちゃんを失恋させる

湯婆婆ちゃんを失恋させるにはサロゲートペアを考慮する必要がありました。
なぜ絵文字を含む文字を1文字ずつに分けるのにArray.fromだけで十分なのか?
という記事で詳細に解説されています。

また、Flutterの湯婆婆にサロゲートペア文字を理解させたら可愛くなった?で紹介されていますが、
Dartの場合Charactersクラスを使って簡単に処理することが出来るそうです。

※サロゲートという言葉の語感は、石黒研究室のサロゲートが出演するサロゲートという映画をご覧いただくと理解しやすいと思います。

湯婆婆失恋バージョン

See the Pen React-Yubaba-LostLove by ShortArrow (@ShortArrow) on CodePen.

失恋バージョンではhandleClick()を書き換えています。

handleClick() {
    const randamIndex = Math.round(Math.random() * (Array.from(this.state.name).length - 1));
    const madeName = Array.from(this.state.name)[randamIndex];
    this.setState({
        clicked: true,
        handleName: madeName
    });
}

恋する乙女バージョンではthis.state.namelengthプロパティから長さを取得していました。
これをArray.from()で配列化してから長さを見るようにしています。

また、substring()を使って切り出していたところを、配列のインデックスで指定して取り出すように変えました。

失恋バージョンへの入力

?田さんのほうから、アプローチを仕掛けてみましょう。
ちょっとハートマークが騒がしいですね。

image.png

失恋バージョンの結果

image.png

この通り、全く緊張感の欠片もありません。
淡々と機械的に読み上げる様を見る限り、
微塵も恋している様子はありませんね。

環境設定

CodePen.ioで書いています。

CodePen.ioでの設定内容

まとめ

多言語でも同じ方法で失恋させることが出来る場合とそうでない場合がありそうです。
この記事を読んで「別の言語で失恋をさせてみたいな」と感じてもらえたらハッピーです。

Excelsior!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React.js/Next.js】styled-componentsでrgbaを利用する時に地味に詰まったのでpolishedで解決した

styled-componentsでrgbaの利用で困った

以下のような実装でした。

const Container = styled.header<{ flag: boolean }>`
  background: ${(props) =>
    props.flag ? rgba(255, 255, 255, 0.07) : rgba(255, 255, 255, 1)};
`;

しかし、名前 'rgba' が見つかりません。と言われる…。

polishedで解決した

polishedを入れれば良かったようでした。

$ yarn add -D polished
import { rgba } from "polished";
const Container = styled.header<{ flag: boolean }>`
  background: ${(props) =>
    props.flag ? rgba(255, 255, 255, 0.07) : rgba(255, 255, 255, 1)};
`;

サンプルっぽいのが以下です。

https://bit.dev/styled-components/polished/color/rgba

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React.js/Next.js】スクロールイベントの検知をしてフラグを切り替える

仕様

  • スクロール中のイベントを検知したらフラグをTrueにする
  • スクロールが止まって定義した時間が経過したらフラグをFalseにする

※サイトへアクセスした時点でフラグが一瞬Trueになっちゃいますが、この実装途中で使わなくなったんで直してないです。
※ただ地味に大変だったので供養したくなりました。

実装

スクロール中は透明になるヘッダーを作ってみました。

const DefaultHeader: FC = () => {
  let timeOutId = 0;
  const SCROLL_INTERVAL_TIME = 500;
  const [scrollStatus, setScrollStatus] = useState(false);

  const makeInactiveScrollStatus = () => {
    setScrollStatus(false);
  };

  const makeActiveScrollStatus = () => {
    clearTimeout(timeOutId);
    setScrollStatus(true);
    timeOutId = setTimeout(makeInactiveScrollStatus, SCROLL_INTERVAL_TIME);
  };

  useEffect(() => {
    if (typeof window !== "undefined") {
      window.addEventListener("scroll", makeActiveScrollStatus);
    }
    return () => {
      if (typeof window !== "undefined" && window.scrollY !== 0) {
        window.removeEventListener("scroll", makeActiveScrollStatus);
      }
    };
  }, []);

  return (
    // styled-componentsにflagを投げる
    <Header scrollStatus={scrollStatus}>
      // 省略
    </Header>
  );
};

const Header = styled.header<{ scrollStatus: boolean }>`
  position: sticky;
  top: 0;
  height: 5.5rem;
  background: ${(props) =>
    props.scrollStatus ? rgba(255, 255, 255, 0.07) : rgba(255, 255, 255, 1)};
  padding: 0 1rem;
  @media screen and (min-width: 48.1em) {
    padding: 0;
  }
`;

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

if (hoge) {~ 比較演算子を使わないIF文がどこまでを「true」とするのかを徹底的に検証してみた【テキスト版】

前提

if (text) {
  return true
} return false

これは、私が実務で初めてこの書き方を目にした時、
「えっ、これ比較演算子書き忘れてるやん」って思ったんだけど(バカ、俺のバカ!)

こういうちゃんとした書き方があることを知り、
ちょっとした衝撃を受けた時のこと。

その後、
私も弱輩ながらこの書き方をマネし初めたが、
色々と上手く行かない…
 

そんなことから、一体この書き方が

どの時が「true」で

どの時に「false」を返すのか

を検証してみたところから始まる。

 
 
 
*********************
前回の記事で記述したが、
今回は動画にも起こしてみようと思ってたけど、
書いてみたら動画があると見辛そうなレイアウトになったので
次回【動画版】として掲載しようと思う。

→前回の記事 【公開】Qiitaに投稿したYoutube動画を自動再生させる!
 
 
 
 

検証環境

・言語:React.js

※少なくともJavaScript系の言語は同じ結果だと思う。
 
 
・コード

// この変数にいろんな物を入れてみることで検証
let text = 'hoge'

const result = () => {
  // ↓ここの判定具合を検証する
  if (text) {
    console.log('text:', text, true) // 条件一致
    return text + ' ←textの中身'
  }
  console.log('text:', text, false) // 条件不一致
  return 'textになんも入ってないで'
}

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>{result()}</p> {/* ←ここで画面に表示 */}
      </header>
      <div></div>
    </div>
  );
}

export default App;

  
 
・表示
見づらいかも知れんが、
画面とコンソールにこのように表示される。

では検証開始!!!!!!!!

 
 
 

1.文字列

その1 中身あるやつ

let text = 'あなたはだんだん「いいね」したくなる'

・画面

・コンソールログ

☆ 結果 = true


その2 空欄

let text = ''

・画面

・コンソールログ

☆ 結果 = false
 
この辺は当然そうでしょう。
 
 

2.数値

その1 プラスの数値

let text = 1

・画面

・コンソールログ

☆ 結果 = true


その2 ゼロ

let text = 0

・画面

・コンソールログ

☆ 結果 = false

まあこの辺も想定内


その3 マイナスの数値

・画面

・コンソールログ

☆ 結果 = true

この辺りから私の心が叫び始める。
「あれぇーゼロより少ないのにtrueなの? なんで?」
どうやらゼロは「無」だけどマイナスは「有」であると判定するようだ。

続いて行ってみる。
 
 
 

3.カッコのやつ

エンジニアが「カッコのやつ」とか言ってると怒られるかも知れんが、
ここではあえてこの呼び方で行こうと思う。

その1 空配列

let text = []

・画面

・コンソールログ

☆ 結果 = true

これはtrue?
とりあえず目には見えない「何か」が存在する
ということで納得するとする。


その2 空オブジェクト

let text = {}

・画面

・コンソールログ

☆ 結果 = true

今度は何か見えた!?どゆこと?
あるの?ないの?
2つ目の「O(オー)」は大文字だし…わけわからんが、
つぎ行ってみよう。
 
 
 

4.真偽値

もうこうなったらまんま入れてみようと思う。

その1 真の値

let text = true

・画面

・コンソールログ

☆ 結果 = true

おっ!trueが画面に表示されてるってことは
文字列になってるってことか!?


その2 偽の値

let text = false

・画面

・コンソールログ

☆ 結果 = false

まーそれはそうですよね。
 
 
 

5.「無いよ」みたいなやつ

その1 ぬる

let text = null

・画面

・コンソールログ

☆ 結果 = false


その2 未定義

let text;

・画面

・コンソールログ

☆ 結果 = false

んーーーーーーundefined…
より分からんくなってきたねーー
 
 
 

6.ちょっとなんて表現していいか分からないやつ

その1

let text = 0 / 0

・画面

・コンソールログ

☆ 結果 = false

falseは何となく分かるけどゼロじゃないの!?
NaNって何?


その2

let text = 1 / 0

・画面

・コンソールログ

☆ 結果 = true

うわぁーまた何か出てきた!
何?Infinityって?
私の世代はDo as Infinityがバッと出てきちゃうのよ。
電卓も「数値じゃありません」って言ってるよ?

怖いわー


その3

let text = 1 / 0

・画面

・コンソールログ

☆ 結果 = false

これはゼロなんかい!
もう寝る!!!
 
 
 

まとめ

そんなこんなで検証した日はいつもよりも深い眠りについた訳だが、
お陰で覚えることができた。

そういうことなので、
「if (hoge) {~ 比較演算子を使わないIF文がどこまでを「true」とするのか」
結論…

「とにかく覚える」

これに限る。
こういう判定になる理由を言語化できるならいいが、
そうでないならベタで覚えるしかないのかな。

無理してこの書き方にする必要はないんだろうが、
もし使うときは、
特に配列とオブジェクトは気をつけたいところ。

そんな気難しいこの書き方、
私は使い続けていこうと思う。

なぜなら…

「なんかカッコええやん」
 

 
ということで次回こそ動画版で記事を書こうと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

三項演算子の使い方(独り言)

突然なのですが。
プログラミングを書いていて、こんな時はありませんか?

・処理の条件をifが使いづらい状況でも使いたい
・スマートに書きたい

こんな時は、三項演算子がおすすめです。

では実際にどのような時に使うのか?
どんな記述の仕方なのか?

例を見ていきたいと思います。co

const test = "hoge"
return(
   <div>{ test ? "trueの処理" : "falseの処理"}</div>
)

このような書き方が「三項演算子と呼ばれるものです。」

今回の例でいうと、testという変数にhogeというString型の文字が入っています。
ifの処理でいうと、この処理はtrueと判定されるのでUIに出てくる文字は【trueの処理】とでてきます。

上の例を参考にして、もう少し分岐を多くすると

const num = 100
<div>{num < 99 ? "numは99より小さいです" : num > 1000 ? "numは1000より大きいです" : num === 100 ? "numは100です" : "hoge"}</div>

複雑にはなりますが、こんな書き方もできます。ちなみにこの例だと「numは100ですと出力されます」
三項演算子は使うことも多いですがあまり分岐が複雑だと、後で大変になるので
できるだけ、簡単な分岐をスマートに実装させたいときにお勧めです!

ではまた。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む