20210604のReactに関する記事は11件です。

React の Provider を一つにまとめてネストを回避する

はじめに React のコードでは、Provider をネストすることがよくあると思いますが、そのネストを回避する方法を提案する記事です。 以下のような、プロバイダのネストを良く思っていない人向けの記事です。 また、この記事を読むと部分適用と関数合成という概念を学習できます。 app.tsx import React from 'react' // UI import { ThemeProvider } from '@material-ui/core/styles' import theme from 'src/app/styles/theme' // 状態管理 import { Provider as ReduxProvider } from 'react-redux' import { store } from 'src/app/redux/store' // web API import { Provider as UrqlProvider } from 'urql' import { client } from 'src/app/graphql/urql' // util import { DndProvider } from 'react-dnd' import { HTML5Backend } from 'react-dnd-html5-backend' // 他の Providers (dummy) declare const FooProvider: React.FC // 内部に Provider を含む関数コンポーネントのダミー declare const BarProviderDependingOnFoo: React.FC // FooProvider に依存するコンポーネント // メインのコンポーネントとその props (dummy) declare const Component: React.FC declare const pageProps: object const App: React.FC = () => { return ( <ThemeProvider theme={theme}> <ReduxProvider store={store}> <UrqlProvider value={client}> <DndProvider backend={HTML5Backend}> <FooProvider> <BarProviderDependingOnFoo> <Component {...pageProps} /> </BarProviderDependingOnFoo> </FooProvider> </DndProvider> </UrqlProvider> </ReduxProvider> </ThemeProvider> ) } export default App ※ FooProvider は 例えば constate で作成した Provider などです。 Provider をまとめる Provider は以下のようにまとめる(合成する)ことができます。 app.tsx // ...前略 import { pipeComponents, partial } from 'src/utils/pipeComponents' // 追加 // ...中略 const Provider = pipeComponents( partial(ThemeProvider, { theme }), partial(ReduxProvider, { store }), partial(UrqlProvider, { value: client }), partial(DndProvider, { backend: HTML5Backend }), FooProvider, BarProviderDependingOnFoo ) const App: React.FC = () => { return ( <Provider> <Component {...pageProps} /> </Provider> ) } export default App pipeComponents の引数としてより先頭側に与えたコンポーネントが、より上流のコンポーネントとなります。 pipeComponents と partial の実装は以下の通りです。 src/utils/pipeComponents.tsx import React from 'react' type Component = React.ComponentType // children のみを prop として持つコンポーネント type AtLeast2 = [Component, Component, ...Component[]] // 型で引数の数を2つ以上に限定 // コンポーネント用部分適用関数 export const partial = <P extends object>( Component: React.ComponentType<P>, props: P ): Component => ({ children }) => React.createElement(Component, props, [children]) // コンポーネント用合成関数 export const pipeComponents = (...components: AtLeast2): Component => { return components.reduce((Acc, Cur) => { return ({ children }) => ( <Acc> <Cur>{children}</Cur> </Acc> ) }) } 実装についてピンとこない方は以下の「補足:部分適用と関数合成」で実装を解説しています。 メリット 可読性(少しだけ読みやすくなる。) 保守性(順番を入れ替えたり、追加したりするのが少し楽になる。変更時の差分が少し分かりやすくなる。) 見た目(好みですが、縦に整列していて良いと思います。) プロバイダ(というよりもコンテキスト)は適切な粒度で作った方がパフォーマンス上良い1ので、プロバイダをたくさん作ること自体は悪くないと思っています。個人的にはプロバイダを増やすことに対する抵抗感が減りました。 補足:部分適用と関数合成 部分適用 部分適用は関数のパラメータの一部を固定して、新しい関数を作る処理です。 下記例では、掛け算をする関数 multiply の引数を 2 で固定して新しい関数 double を作成しています。 部分適用をしてくれる関数として ramda ライブラリを使います。 import { partial } from 'ramda' const multiply = (a, b) => a * b const double = partial(multiply2, [2]) double(2) //=> 4 「Provider をまとめる」に記載した partial は、children prop 以外の props を固定したコンポーネントを作成します。言い換えると、children のみ を引数として取るコンポーネントを作成します。 関数合成 関数合成はざっくりと説明すると複数の関数から一つの関数を作る処理です。 下記例では二つの関数を合成する関数(pipe2)を使って、double と increment を合成し、doubleAndIncという新しい関数を作成しています。 const pipe2 = (fn1, fn2) => (num) => fn2(fn1(num)) const double = (num) => num * 2 const increment = (num) => num + 1 const doubleAndInc = pipe2(double, increment) doubleAndInc(1) // 3 コンポーネントは、children 等 の props を引数に取り、UI(ReactElement)を出力する関数と考えられます。 「Provider をまとめる」に記載した pipeComponents では、children のみ を引数として取る複数の「関数」を合成しています。 部分適用と関数合成を組み合わせて使う 関数の形(シグネチャ)が異なる関数でも、部分適用によって関数の形を統一させることにより、合成することができるようになります。 import { partial } from 'ramda' const pipe2 = (fn1, fn2) => (num) => fn2(fn1(num)) const multiply = (a, b) => a * b const increment = (num) => num + 1 // ↓ 部分適用なしだと pipe2 で合成できない const doubleAndInc_ng = (num) => multiply(increment(num), /* ❗ 引数が不足 */) // ↓ 部分適用ありだと pipe2 で合成できる const double = partial(multiply, [2]) const doubleAndInc_ok = (num) => double(increment(num)) // ↓ 部分適用と関数合成を組み合わせて使う const doubleAndInc = pipe2( partial(multiply,[2]), increment ) doubleAndInc(1) // 3 「Provider をまとめる」に記載した app.tsx でも部分適用partial と関数合成pipeComponents を組み合わせています。 参考 別記事(React の Context を分割するとはどういうことか、分割すると何が良いのか) ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】react-routerのhooks

react-routerのhooksの種類 useHistory ページ遷移させるときに使用するhistoryオブジェクトを取得できる const history = useHistory(); history.push('/'); history.goBack(); useLocation 現在のページのURLのpathやqueryなどを取得できる const location = useLocation(); location.path location.search useParams URLパラメータを取得できる <Route path="/sample/:name"> と定義したページにアクセスした際に下記の記述で :name の値を取得できる const { name } = useParams();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

react-router-domでrouterが動かない場合はrouter以下をdivで囲む

動かない <Router> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/dashboard">Dashboard</Link> </li> </ul> <hr /> {/* A <Switch> looks through all its children <Route> elements and renders the first one whose path matches the current URL. Use a <Switch> any time you have multiple routes, but you want only one of them to render at a time */} <Switch> <Route exact path="/"> <Home /> </Route> <Route path="/about"> <About /> </Route> <Route path="/dashboard"> <Dashboard /> </Route> </Switch> </Router> 動く <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/dashboard">Dashboard</Link> </li> </ul> <hr /> {/* A <Switch> looks through all its children <Route> elements and renders the first one whose path matches the current URL. Use a <Switch> any time you have multiple routes, but you want only one of them to render at a time */} <Switch> <Route exact path="/"> <Home /> </Route> <Route path="/about"> <About /> </Route> <Route path="/dashboard"> <Dashboard /> </Route> </Switch> </div> </Router> routerの中が単一の要素でないと動かないらしい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Final Form #02 Render Props を使って、かんたんにバリデーションを実装する

この記事を読むと幸せになれそうな人 Controlled Component (React.useState や Redux を使う方法)で大きめのフォームを構築する時、クライアントサイドでのバリデーションを実装したりすると、ボイラープレートコードが多すぎて辟易してしまうと思います。 そんな人には、この React Final Form がオススメかもしれません。 続き物です #01『かんたんにフォームを構築する』 #02『Render Props を使って、かんたんにバリデーションを実装する』 ←今ここ 0. emailアドレス欄を追加 まずは、前回に続いて、emailアドレスの入力欄を追加します。(バリデーションの題材としてはこっちの方が手っ取り早いので) pages/react-final-forms/index.tsx const waitMs = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const initialValues = { name: "aa", + email: "" } as const; type ValuesType = typeof initialValues; const ReactFinalFormPage: NextPage = () => { type HandleSubmit = FormProps<ValuesType, ValuesType>["onSubmit"]; const handleSubmit: HandleSubmit = async (s) => { await waitMs(1000); window.alert(`JSON: ${JSON.stringify(s)}`); // 例) JSON: {"name":"山田太郎"} }; return ( <Form onSubmit={handleSubmit} initialValues={initialValues} render={({ handleSubmit }) => ( <form onSubmit={handleSubmit}> <Field name="name" component="input" /> + <Field name="email" component="input" /> <button>送信</button> </form> )} /> ); }; export default ReactFinalFormPage; 1. Fieldで、 Render Props を使って書き換え Fieldの機能はそのままで、 component Prop を使わずに、 Render Prop を使った書き方に変えてみましょう。後々バリデーションメッセージを表示したり、Material UI のような UI ライブラリを使う際ためには、おそらくこの書き方に変える必要があるでしょう。 pages/react-final-forms/index.tsx - <Field name="email" component="input" /> + <Field<string> name="email" render={({ input }) => <input {...input} />} /> <Field<string> ...> の部分は、わかりにくいですが、Fieldコンポーネントに、型引数として、stringを渡せているみたいです。こんな変なこともできるんですね。 Render Prop の引数は、Field Render Props 型になります。 関数の引数オブジェクトの input プロパティはオブジェクトになっています。基本的には、この内容を全て <input/> 要素に渡すことになっています。スプレッド構文を使ってまとめて渡しましょう。 2. バリデータの追加 それでは、お待ちかねのバリデーションの実装に移ります。 次の const 宣言をトップレベルに書きましょう。 pages/react-final-forms/index.tsx const validateEmail: FieldValidator<string> = (value): string[] | undefined => { if (!value || value.length === 0) return ["必須要素です"]; const emailRegexp = /^[a-zA-Z0-9_+-]+(.[a-zA-Z0-9_+-]+)*@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/; if (!emailRegexp.test(value)) return ["Eメールアドレスのフォーマットに適していません"]; return undefined; }; React Final Form では、Fieldに追加するバリデーション関数は FieldValidator<T> 型になります。 返り値としては、エラーがない時には undefined を返し、エラーの時には、エラーを表す何らかの値を返しましょう。 実は、async 関数もOKです。(今回は使いません) (今回は、string[]型の値に決めていますが、返り値の型は元々決まっていないので、自分で決めましょう。) メールアドレスの正規表現は下のページを参考にしています。 これを、Fieldのコンポーネントに実装していきましょう。 pages/react-final-forms/index.tsx <Field<string> name="email" validate={validateEmail} render={({ input, meta }) => ( <div> <input {...input} /> <span> {meta.error && meta.touched && meta.error.map((s: string) => <small>{s}</small>)} </span> </div> )} /> まず、validate Propに先ほどのバリデーション関数を渡します。 すると、Render Props の meta.error にバリデーション関数が返したエラーが入って渡されてきます。 meta.error && meta.touched && を付けていますが、これは、 error が undefined なら何も表示しない。 フィールドが、フォーカスを外されたことがない場合にも、何も表示しない。 meta.touched は、一度フォーカスされたあとフォーカスが外れたら true になるフラグ ことを表しています。 Field Render Props のドキュメントを見ると、他にも様々なフラグ(meta.xxx)があります。それらを使うと、エラーメッセージの表示の切り替えのタイミングを様々に変えたり、初期値から変更されたフィールドだけを強調したりすることもできます。 3. バリデーションが成功していない場合にボタンをdisabledにする ついでに、バリデーションが成功していない場合には、ボタンを disabled にしてしまいましょう。 こうしておかないと、入力値が間違っていても送信できてしまいますからね。 pages/react-final-forms/index.tsx <Form onSubmit={handleSubmit} initialValues={initialValues} - render={({ handleSubmit }) => ( + render={({ handleSubmit, valid }) => ( <form onSubmit={handleSubmit}> <Field name="name" component="input" /> <Field<string> name="email" validate={validateEmail} render={({ input, meta }) => ( <div> <input {...input} /> <span> {meta.error && meta.touched && meta.error.map((s: string) => <small>{s}</small>)} </span> </div> )} /> - <button>送信</button> + <button disabled={!valid}>送信</button> </form> )} /> Form の Render Props (ドキュメント : FormRenderProps ) には、valid Prop があります。中のフィールドのバリデーションが全て成功している時にこの値が true になります。 これによって、バリデーションエラーが出ているときに、ボタンを押せなくすることができました。 4. エラーメッセージをコンポーネント化 エラーメッセージの記述が長ったらしくなっていたので、コンポーネントに切り出して、記述を楽にします。 pages/react-final-forms/index.tsx <Field<string> name="email" validate={validateEmail} render={({ input, meta }) => ( <div> <input {...input} /> - <span> - {meta.error && - meta.touched && - meta.error.map((s: string) => <small>{s}</small>)} - </span> + <ErrorMsg hidden={meta.touched} msgs={meta.error}/> </div> )} /> コンポーネントの定義 type ErrorMsgProps = { hidden?: boolean; msgs: string[] }; const ErrorMsg: React.FC<ErrorMsgProps> = ({ hidden, msgs }) => ( <span>{msgs && hidden && msgs.map((s) => <small>{s}</small>)}</span> ); 5. 名前にもバリデーションをつける 名前にも、文字列が空のときにエラーを返すバリデータを追加します。 コンポーネント化したので、コードも短くてラクラクですね。 pages/react-final-forms/index.tsx const validateRequiredString: FieldValidator<string> = ( value ): string[] | undefined => { if (!value || value.length === 0) return ["必須要素です"]; return undefined; }; pages/react-final-forms/index.tsx <form onSubmit={handleSubmit}> - <Field name="name" component="input" /> + <Field<string> + name="name" + validate={validateRequiredString} + render={({ input, meta }) => ( + <div> + <input {...input} /> + <ErrorMsg hidden={meta.touched} msgs={meta.error} /> + </div> + )} + /> <Field<string> name="email" validate={validateEmail} render={({ input, meta }) => ( <div> <input {...input} /> <ErrorMsg hidden={meta.touched} msgs={meta.error} /> </div> )} /> <button disabled={!valid}>送信</button> </form> )} /> ); }; export default ReactFinalFormPage; まとめ いかがだったでしょうか? Filed の Render Props を使えば、一貫した方法で柔軟にフィールドを制御したり、バリデーションを実装したりできることがわかったと思います。 送信ボタンの活/不活も、同様のインターフェースで制御できましたね。 次回以降はまだ未定です。 コード全容 pages/react-final-forms/index.tsx import { FieldValidator } from "final-form"; import { NextPage } from "next"; import { Field, Form, FormProps } from "react-final-form"; const waitMs = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const initialValues = { name: "aa", email: "", } as const; type ValuesType = typeof initialValues; const validateRequiredString: FieldValidator<string> = ( value ): string[] | undefined => { if (!value || value.length === 0) return ["必須要素です"]; return undefined; }; const validateEmail: FieldValidator<string> = (value): string[] | undefined => { if (!value || value.length === 0) return ["必須要素です"]; // from https://www.javadrive.jp/regex-basic/sample/index13.html#section1 const emailRegexp = /^[a-zA-Z0-9_+-]+(.[a-zA-Z0-9_+-]+)*@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/; if (!emailRegexp.test(value)) return ["Eメールアドレスのフォーマットに適していません"]; return undefined; }; type ErrorMsgProps = { hidden?: boolean; msgs: string[] }; const ErrorMsg: React.FC<ErrorMsgProps> = ({ hidden, msgs }) => ( <span>{msgs && hidden && msgs.map((s) => <small>{s}</small>)}</span> ); const ReactFinalFormPage: NextPage = () => { type HandleSubmit = FormProps<ValuesType, ValuesType>["onSubmit"]; const handleSubmit: HandleSubmit = async (s) => { await waitMs(1000); window.alert(`JSON: ${JSON.stringify(s)}`); }; return ( <Form onSubmit={handleSubmit} initialValues={initialValues} render={({ handleSubmit, valid }) => ( <form onSubmit={handleSubmit}> <Field<string> name="name" validate={validateRequiredString} render={({ input, meta }) => ( <div> <input {...input} /> <ErrorMsg hidden={meta.touched} msgs={meta.error} /> </div> )} /> <Field<string> name="email" validate={validateEmail} render={({ input, meta }) => ( <div> <input {...input} /> <ErrorMsg hidden={meta.touched} msgs={meta.error} /> </div> )} /> <button disabled={!valid}>送信</button> </form> )} /> ); }; export default ReactFinalFormPage; See also: Final Form と、そのReactバインディングである React Final Form のドキュメントです この動画でのライブコーディングも、大いに参考になると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSXは<script type="text/babel">で読み込む!!

やりたいこと Reactだけを使ってHello, World!を出力したかった。 参考サイト:https://sbfl.net/blog/2019/02/20/react-only-tutorial/ 起こったこと JSXで文法はあってるのにUncaught SyntaxError: Unexpected token '<'エラーが起きて詰んだ。 前提条件 ReactとbabelをCDNで読み込んでいる。 環境 react: v16.14.0 react-dom: v16.14.0 babel: v6.26.0 サーバー:Live Server v5.6.1(VScodeの拡張機能) 問題のCode HTML <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>孤独ったー</title> <!-- ReactをCDNで呼び出す --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- 自分で記述するスクリプト --> <script type="text/javascript" src="main.jsx"></script> </head> <body> <!-- React の描画対象を準備する --> <div id="app"></div> </body> </html> JSX function App() { return <div>Hello React!</div>; } const target = document.querySelector('#app'); ReactDOM.render(<App/>, target); 解決策 HTMLの自分で記述するスクリプトのtypeを間違って指定していた。 誤:<script type="text/javascript"> 正:<script type="text/babel"> 最後に そりゃtype間違えば正しく動かないのは理解できたけど。。。 エラー箇所と全く違うところをエラーポイントとして怒らないでほしいな!!!!!!!!!(怒) 参考サイトなど 正真正銘ぼReactだけの不純物なしでReact入門 https://sbfl.net/blog/2019/02/20/react-only-tutorial/ Unexpected tokenとは?Unexpected tokenの対処法を紹介! https://www.fenet.jp/dotnet/column/environment/7497/#i-2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

当たり前だけどJSXは<script type="text/babel">で読み込む!!

やりたいこと Reactだけを使ってHello, World!を出力したかった。 参考サイト:https://sbfl.net/blog/2019/02/20/react-only-tutorial/ 起こったこと JSXで文法はあってるのにUncaught SyntaxError: Unexpected token '<'エラーが起きて詰んだ。 前提条件 ReactとbabelをCDNで読み込んでいる。 環境 react: v16.14.0 react-dom: v16.14.0 babel: v6.26.0 サーバー:Live Server v5.6.1(VScodeの拡張機能) 問題のCode HTML <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>孤独ったー</title> <!-- ReactをCDNで呼び出す --> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- 自分で記述するスクリプト --> <script type="text/javascript" src="main.jsx"></script> </head> <body> <!-- React の描画対象を準備する --> <div id="app"></div> </body> </html> JSX function App() { return <div>Hello React!</div>; } const target = document.querySelector('#app'); ReactDOM.render(<App/>, target); 解決策 HTMLの自分で記述するスクリプトのtypeを間違って指定していた。 誤:<script type="text/javascript"> 正:<script type="text/babel"> なぜこのような事が起こるのか 私がまだReactとJSXの仕組みをよくわかってないことが原因なんですけど、つまりは以下のようになってるからなんですね〜 JSXがレンダリングされる仕組み [JSX]→[Babel]→[Javascript]→[HTML] JSXがBabelによってJavascriptに翻訳される 翻訳されたJavascriptがHTMLによって読み込まれる 表示される こういう事だったんですね。 最後に そりゃtype間違えば正しく動かないのは理解できたけど。。。 エラー箇所と全く違うところをエラーポイントとして怒らないでほしいな!!!!!!!!!(怒) 参考サイトなど
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactの新規プロジェクト作成方法

本記事の目的 React + TypeScriptで開発する際の新規プロジェクトの作成方法と、それに関する備忘録を記録するのが目的。 Reactプロジェクト新規作成コマンド Reactの新規プロジェクトの作成にはコマンドライン上で次のコマンドを実行する。 $ npx create-react-app プロジェクト名 --template=typescript 補足説明 npx... npmパッケージで提供されているコマンドを実行するためのコマンド。 主な特徴として、該当パッケージが既にインストールされていればそれが実行され、そうでなければその場限りで最新版がダウンロードされて実行される。今回のような使用頻度の低い新規プロジェクト作成コマンドなどの使用に有用。 create-react-app... Reactの新規プロジェクト作成コマンド。 プロジェクト名... 作成する任意のプロジェクト名を入力。ex.sample_app など。 --template=typescript...Typescriptを用いて開発する際に指定するオプション。作成するプロジェクトの下敷きにするテンプレートを指定することができる。 このオプションを指定しなかった場合にはデフォルトで素のjavascriptで開発するためのテンプレートが指定される。 作成に成功したプロジェクトを起動させるコマンド 新規作成に成功したプロジェクトのルートディレクトリに移動し、以下のコマンドを実行。 $ yarn start HTTPサーバが3000番ポートで起動してアプリケーションが稼働し、ブラウザ上で表示される。 Reactのマークがグルグルと回る画面が表示されれば成功。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WordPressのContact Form 7を使いAPI経由でフォームと送信する

CMSサービス、フォームメールのバックエンドサービスが出始めていますが、クライアントの都合でなかなかそういったサービスを使えないこともあります。 Wordpressを使いつつ、HeadlessCMSとして使う想定の中でフォーム送信機能もWordpress側で持たせてあげたい、という要件はきっとある(はず)。 ※ Wordpress全般に言えることですが、Contact Form7はちょこちょこ脆弱性が見つかって攻撃されているなどの問題もあります。そういうところも含めてWordPressでの運用を愛せる方が自己責任で行ってください なんでこの記事をかいたのか Contact Form7のAPIを叩く記事はQiitaにもあったが、記述が片手落ちでそのとおりにやってもうまくいかなかった。 よりシンプルに十全な記事を書くことを目的としています。 参考にしたURL 前提 WordpressにContact Form7が入っている 実装サンプルはReact typescript fetchですがなんでも URL エンドポイント Contact Form 7のエンドポイントはこちらになります。 https://<サイトのURL>/wp-json/contact-form-7/v1/contact-forms//feedback FORM_IDには、フォームのショートコードに書かれているIDを入れてあげます [contact-form-7 id="<この数字>" title="コンタクトフォーム"] <form onSubmit={this.handleSubmit}> <input type="text" placeholder="" name="your-name" value={this.state.name} onChange={this.handleChange} /> </form> Reactの場合、formのonSubmitのイベントで処理するとかんたんです。 name属性には、Contact Form7のフォームに指定したnameを入れてあげましょう const API_URL = 'https://<サイトのURL>/wp-json/contact-form-7/v1/contact-forms/<FORM_ID>/feedback' handleSubmit = async (event) => { event.preventDefault(); const formElement = event.target; const body = new FormData(formElement); const res = await fetch(API_URL, { method: 'POST', body: body, }) } あとはサーバーサイドのバリデーション結果や送信完了はレスポンスで返ってきますので、そのあたりをうまく処理してあげたら完了です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel:部分的に使用しているreactにview変数を受け渡す方法

Laravel:部分的に使用しているreactにview変数を受け渡す方法 構成 基本はbladeを使用し、reactは特定画面の指定div要素内のみで使用 目的 controllerから渡されたviewの変数をreactで使用したい 対応方法 javascriptのglobal変数として渡すことも可能だが、今回はdata属性にパラメータを指定して受け渡す。 受け渡し変数 HogeController.php $fuga = json_encode([ ['key' => 'key1', 'value' => 'hoge1'], ['key' => 'key2', 'value' => 'hoge2'], ['key' => 'key3', 'value' => 'hoge3'], ]); return view('home', compact('fuga')); hoge.blade.php <!-- idおよびblade部分は任意の文字列--> <div id='react' data-blade={{$fuga}}/> app.tsx componentDidMount() { const element = document.getElementById('react'); if (element && element.dataset.blade) { const object = JSON.parse(element.dataset.blade); console.log(object); } } 所感 javascriptのglobal変数に持たせるやり方もありますが、個人的にはこちらのほうが管理しやすいと思います。 vueのv-bindは便利ですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Typescript 環境構築メモ

プロジェクト テンプレート作りかた $ npx create-react-app my_app --template typescript 起動 $ yarn start カレントディレクトリにあるファイルをインポートするときは import file from './file_name' たとえば、App.tsx import React from "react"; function App() { return( <div className="Main"> <header className="Main-header"> aaaa </div> </div> ); } export default App の場合 import App from "./App"; たとえばcss cssのファイル名がApp.cssなら import App_css from "./App.css"; import の次に来る "App", "App_css", "file" とかは {App}みたいな感じで returnの中に書いたら使える。 命名は自由、ほんとうはどうかしらないけど ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); の中にある<App />のAppを例えば、 import aaaa from "./aaaa" が存在したとして <aaaa /> に変えれば、最初に表示されるページをカレントディレクトリにあるaaaa.tsxに書き込まれた内容に変えることができます functionを入れることが可能なので function bbbb() { return ( なかみは何でもok ) } <bbbb /> に変えることで中身をbbbbのreturn内に書き込まれたものに変えることができます
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでReactのホットリロードが効かない

はじめに Docker上でReactとTypeScriptと使って開発をしている時に、ファイル保存時に自動的にブラウザに反映(hot reload)されなくなったので、その解決策をここに備忘録として書き残します。 開発環境 Windows10 Docker for windows React 17.0.2 TypeScript 4.3.2 解決策 create-react-app/Trouble shootingに書かれている通りに、.envファイルを作成し、polling modeをtrueと記述しました。が直りませんでした。おそらくDockerに何かありそうです。 If the project runs inside a virtual machine such as (a Vagrant provisioned) >VirtualBox, create an .env file in your project directory if it doesn’t exist, and >add CHOKIDAR_USEPOLLING=true to it. This ensures that the next time you run npm >start, the watcher uses the polling mode, as necessary inside a VM. React-create-app/Trouble shooting Dockerにも追加 docker-compose.ymlに.envと同様の記述しました。そしたら、ちゃんとhot relodeが効くようになりました。 docker-compose.yml environment: - CHOKIDAR_USEPOLLING=true あとがき 普段macで開発をしているので、windowsで何かあるとwindowsのせいにすることをやめようと思います。しっかりと問題の本質を見極める必要がありそうですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む