20220113のReactに関する記事は4件です。

ReactでReact Routerを使いログインを実装する

はじめに 今回はReactでReact Router を使ってログインの実装を行います。 React Routerを使えばサイト上にリンクを設置することができ、ページの行き来が可能になります。 また認証されてないユーザーに対してページを表示させないということもできます。 インストール 今回はv6を使用します。 npm install react-router-dom@6 公式サイトURL https://reactrouter.com/docs/en/v6/getting-started/installation サイト構築 まずは簡単なサイトをReact Routerを使って構築します。 App.js import * as React from "react"; import { BrowserRouter, Routes, Route, Link } from "react-router-dom"; const AppBar = () => { return ( <> <Link to="/">home</Link> <Link to="/login">login</Link> </> ) } const Home = () => <p>Home</p> const Login = () => <p>Login</p> function App() { return ( <BrowserRouter> <AppBar /> <Routes> <Route path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> </Routes> </BrowserRouter> ); } export default App; AppBarで返されるLinkコンポーネントを使ってページの移動を行います。 loginのリンクをクリックすれば/loginに飛ばされパラグラフのLoginが表示されます。 AppBarはRoutesの外側にあるのでどのページでも表示されるようになっています。 仮認証実装 次に認証されていないユーザーに対してページを表示させないようにします。どのように認証するかはReactのContextを使って行います。 AuthProvider.js import React, { createContext, useContext, useState } from 'react'; const AuthContext = React.createContext(); const AuthProvider = ({children}) => { const [authenticated,setAuthenticated] = React.useState(false); function login () { setAuthenticated(true); } function logout () { setAuthenticated(false); } const auth = { authenticated, login, logout } return ( <AuthContext.Provider value={auth}> {children} </AuthContext.Provider> ); } const useAuth = () => { const context = useContext(AuthContext); return context; }; export {AuthProvider,useAuth} ログインページ実装 次にAuthProviderとuseAuthを使って認証されてないユーザーに対してログインページに戻す機能を追加します。 App.js import * as React from "react"; import { BrowserRouter, Routes, Route, Link, Navigate } from "react-router-dom"; import {AuthProvider, useAuth} from './AuthProvider'; const AppBar = () => { return ( <> <Link to="/">home</Link> <Link to="/login">login</Link> <Link to="/private">private</Link> </> ); } const Home = () => <p>Home</p> const Login = () => { const { authenticated, login, logout } = useAuth(); return ( <> { authenticated? <button onClick={logout}>LogOut</button> : <button onClick={login}>LogIn</button> } </> ); } function Authenticated({ children }) { const { authenticated } = useAuth(); return authenticated === true ? children : <Navigate to="/login" replace />; } const Private = () => <p>Private</p> function App() { return ( <BrowserRouter> <AuthProvider> <AppBar /> <Routes> <Route path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> <Route path="/private" element={<Authenticated> <Private /> </Authenticated>} /> </Routes> </AuthProvider> </BrowserRouter> ); } export default App; ログインページにloginまたはlogoutするボタンを追加しました。 これでログインしていないユーザーはプライベートのページを表示することはできません。 LogInのボタンを押すとauthenticatedがtrueになりPrivateのコンポーネントが表示されます。 ログインしてない状態で/privateのリンクを踏むと/loginに飛ばされます。 これでログインの実装ができました。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React x Typescriptでローカルの動画を再生する

概要 動画を公開ストレージに上げてそのリンク経由で動画視聴するのではなく、動画をプロジェクト内部に置いて手軽にそれを再生したい時ってあるのかなーと思います。 ローカルの動画を再生するにあたって、若干ハマってしまったので整理します。 環境 $ node -v v16.13.1 $ npm -v 8.1.2 準備 今回はcreate-react-appでプロジェクトを作り、react-playerというライブラリを採用しました。インストールはyarnを使う場合は以下になります。 ※「create-react-app」の@5.0.0のバージョン指定は2022年1月時点でエラー出る対策です。これは時期性のものと考えられるので、適宜変更ください。 ※動画をインポートする部分のエッセンスはReact x Typescript x create-react-appの組み合わせであれば、videoタグでも同様と思います。 npx create-react-app@5.0.0 video_play_demo --template typescript yarn add react-player 実装 ハマった部分は後述します。とりあえず結論だけ見たいという方は以下のサンプルを参照ください。 とあるコンポーネント import ReactPlayer from "react-player" // src直下にassetsフォルダを作り、そこに動画を置きました。 import VideoGuideLocalPath from './assets/video_guide.mp4' export const VideoGuide: React.FC = () => { return ( <ReactPlayer url={VideoGuideLocalPath} controls /> ) } react-app-env.d.ts // mp4以外であれば、*.mp4の拡張子の部分を変更ください declare module '*.mp4' { const src: string; export default src; } ハマったこと ファイルパスを直接指定すると、何も表示されない 正直、原因はわかってません。。。わかる方コメント等で教えてください。 ただ解決方法としては、ファイルパスをimportする必要がありました。 // URL直接指定のみだと、何も表示されない。この1文は参考にしないで。 <ReactPlayer url={'./assets/video_guide.mp4'} /> importすると、ts2307エラーが発生する // Cannot find module './assets/video_guide.mp4' or its corresponding type declarations.ts(2307) import VideoGuideLocalPath from './assets/video_guide.mp4' create-react-appの以下のissueによると、Typescript側のエラーらしいです(ほんまかいな)。 issueの通り、react-app-env.d.tsに対してmoduleとしてmp4の拡張子を受け入れるようなコードを書くと解決しました。 react-app-env.d.ts /// <reference types="react-scripts" /> // mp4以外であれば、*.mp4の拡張子の部分を変更ください declare module '*.mp4' { const src: string; export default src; } controlsオプションを指定しないと動画が再生されない controlsのオプション指定しないと初期フレームの絵だけ表示されて、動画が再生されませんでした。 メディアボタン(ex.再生ボタン、一時指定ボタン)を表示するオプションを入れないと再生が開始できないので、要注意です。 ※YouTubeのURLを直接指定だと、指定せずとも再生ボタンが表示されるので意外とハマりポイントではと思っています。 controlsオプションないと動画再生されない import ReactPlayer from "react-player" import VideoGuideLocalPath from './assets/video_guide.mp4' export const VideoGuide: React.FC = () => { return ( // メディアボタン(ex.再生ボタン、一時指定ボタン)は表示されない <ReactPlayer url={VideoGuideLocalPath} /> ) } 所感 ローカルの動画再生くらい、ライブラリ使えば大したことないやと思ってたのですが、意外とハマりどころ多くて、整理したくなりました。俺だったら、私だったらこうするぜとかあればフィードバックお待ちしてますー。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Warning: React has detected a change in the order of Hooks called by X でハマる

何をしていたか(悪いコード)  React Native で、とあるアプリで、アカウント情報を表示する画面を作成していた。  ReactNavigation を利用していた。  処理の概要は以下 export default function MyPage { // ユーザ情報 const [user, setUser] = useState(); // ユーザ情報取得処理(あとで再利用する) const userCheck = async () => { const user = await getUser(); setUser(user); } // 画面表示開始時に一度だけ読み取る useEffect(userCheck, []); // ユーザ情報がなければ処理中を表示 if (!user) { return ( <Text>処理中</Text> ); } // ここから本画面 画面遷移用にnavigation 確保 const navigation = useNavigation(); return ( <Text>本画面</Text> {/* 実際は、画面遷移などをする処理がある */} ); 先に結論  useNavigation も立派な Hook なので、条件によって呼ばれたり呼ばれなかったりするとこのエラーになります。 何が起きたか  処理的には問題名けど、以下のエラーが表示されてビビる Warning: React has detected a change in the order of Hooks called by MyPage. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks Previous render Next render ------------------------------------------------------ 1. useState useState 2. useState useState 3. useEffect useEffect 4. undefined useContext ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 何をしたか  ひとまずURL https://reactjs.org/link/rules-of-hooks  の記載があるので、皿の目で読む。  翻訳などを使って、以下のように理解 Hooks は、レンダリング毎に、同じ順序、同じ量、同じものを毎回呼ばれるようにしなきゃいかんよ 上を読んでもハマる。どう考えたか useState は毎度同じものが同じ順序で呼び出されるはず useEffect も useState の後に呼び出されているし、?のURL記載事項には反していないはず あれ? useContext ってなんだっけ? 使ってたっけ? 結局何だったか  useNavigation がHookであることを忘れていた。  useNavigation は、内部で useContext を使っているので、この順序になっていた。  state の条件により、 useNavigation が呼ばれたり呼ばれなかったりすると、このエラーになるようだ。 良いコード export default function MyPage { // ユーザ情報 const [user, setUser] = useState(); // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ // 画面遷移用にnavigation 確保(条件に左右されず useNavigation は呼ばれるようにしないとエラーになるぞ) const navigation = useNavigation(); // ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ // ユーザ情報取得処理(あとで再利用する) const userCheck = async () => { const user = await getUser(); setUser(user); } // 画面表示開始時に一度だけ読み取る useEffect(userCheck, []); // ユーザ情報がなければ処理中を表示 if (!user) { return ( <Text>処理中</Text> ); } // ここから本画面 return ( <Text>本画面</Text> {/* 実際は、画面遷移などをする処理がある */} ); 教訓 ライブラリをじゃんじゃん使うのはいいが、中で何をしているのか、特に Hooks については気を付けよう use という言葉から、Hooks だと連想できるようになろう 正常に動作するので、最悪放置しようと思ったけど、そんな自分にばいばいきん
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactのindex.htmlのコメントを翻訳

今後Reactの知識を徐々に共有していきます。 翻訳に使用したもの DeepL(ディープエルと呼びます。) Google翻訳よりも日本語らしく翻訳してくれるので、オススメです。 public/index.htmlを翻訳したコード index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- manifest.json は、ユーザーのモバイルデバイスまたはデスクトップにWebアプリをインストールする際に使用されるメタデータを提供します。 https://developers.google.com/web/fundamentals/web-app-manifest/ をご覧ください。 --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- 上のタグで`%PUBLIC_URL%`を使っていることに注目してください。 これは、ビルド時に`public`フォルダの URL に置き換えられます。 HTMLから参照できるのは、`public`フォルダの中のファイルだけです。 "/favicon.ico "や "favicon.ico "とは異なり、"%PUBLIC_URL%/favicon.ico "の場合は、 クライアントサイドのルーティングと非ルートのパブリックURLの両方で正しく機能します。 非ルート公開URLの設定方法は、`npm run build`を実行することで確認できます。 --> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- このHTMLファイルは、テンプレートです。 ブラウザで直接開くと、空のページが表示されます。 このファイルには、ウェブフォント、メタタグ、アナリティクスを追加することができます。 ビルドステップでは、バンドルされたスクリプトを<body>タグに配置します。 開発を始めるには、`npm start`または`yarn start`を実行します。 本番用のバンドルを作成するには、`npm run build`または`yarn build`を実行します。 --> </body> </html> まとめ この記事が良いと思った方は、LGTMをしていただければ嬉しいです! フォローも是非お願い致します(^^)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む