20210912のReactに関する記事は5件です。

Reactを基本からまとめてみた【10】【React Hook (useState)③】

はじめに 学習するに至った経緯 2020年より、未経験からエンジニアへの転職を目指し、某プログラミングスクールへ通う。入学後、『Ruby』を未経験から学ぶ人が多いのと『Ruby』の求人が思っていた以上に少ないので、卒業後、フロントエンドのエンジニアを目指す事に。 Reactの学習した事を言語化し、認識の深化による備忘録として記載。 useStateとは 関数コンポーネント内でstateを保持するためのフック。 フック(Hookとは) React16.8で追加された新機能で、関数コンポーネントにstateやライフサイクルといったReactの機能を"接続する(hook into)"ための関数のこと。 useStateを使うと何ができるのか useStateを用いることで、コンポーネントに状態(state)を持たせることができる。 状態(state)とは、コンポーネントに管理され、プライベートであるべき値のこと。 useStateの使い方 sample.js 1.useStateによるstateの宣言 const [state:現在の状態, setState:更新関数] = useState(initialState:初期値) 2.stateの更新 setState:更新関数(newState:新しい値) 3.具体例 const [messeage, setMesseage] = useState('Torahack is comment') const [likes, setLikes] = useState(0) const [isPublished, setIsPublished] = useState(false) setIsPublished(true) 引数を使って更新する sample.js //入力ホームでよく使うソースコード import React, {useState} from 'react'; const TextInput = () => { const [name, setName] = useState('') const handleName = (event) => { setName(event.target.value) } //onChangeイベントでhandleName関数に渡す //handleName関数のパラメータであるeventを更新関数に渡す return ( <input onChnage={(event:onChangeイベントの戻り値) => handleName(event)} type={'text'} value={name} /> ); }; prevStateを活用する prevState とは 以前の状態 にアクセス・参照して 値を変更する こと。 sample.js //useStateの更新関数で使える特殊なprevState import React, {useState} from 'react'; //prevStateは更新前のstate const Counter = () => { const [count, setCount] = useState(0) const countUp = () => { setCount(prevState => prevState +1) } const countDown = () => { setCount(prevState => prevState -1) } //prevStateは更新を加えてreturn return ( <div> <p>現在のカウント数:{count}</p> <button onClick={countUp}>up</button> <button onClick={countDown}>Down</button> </div>  ); }; ON/OFFを切り替えるボタン sample.js import React, {useState} from 'react'; const ToggleButton = () => { const [open, setOpne] = useState(false) const toggle = () => { setOpen(prevState => !prevState) } //prevStateで受け取った値を!で反転してreturnする return ( <button onClick={toggle}> //参考演算子によってopenがtrune/falseで表示を切り替える {open ? 'open':'close'} </button> ); }; export default ToggleButton; 参考サイト #07 新・日本一わかりやすいReact入門【基礎編】頻出するuseStateのケース3選 (React) prevState について
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails + React 画像読み込み方法

手順 画像ファイルを app/assets/images へ配置 config/webpacker.yml に追記 jsx ファイルに Component を作成 1. 画像ファイルを app/assets/images へ配置 適当な画像ファイルをapp/assets/imagesへ配置します。 2. config/webpacker.yml に追記 config/webpacker.yml # Additional paths webpack should lookup modules # ['app/assets', 'engine/foo/app/assets'] # resolved_pathsを下記のように変更 resolved_paths: ["app/assets/images"] 3. jsx ファイルに Component を作成 test.jsx import Image from 'test.png'; export default function TestComponent(props) { // ImageComponent 作成 const ImageComponent = p => <img src={Image} /> return ( // ImageComponent 読み込み <ImageComponent></ImageComponent> ); } 参考 Rails × React で画像を読み込む方法 https://forestbook-freelance.com/2021/04/12/rails-x-react-%E3%81%A7%E7%94%BB%E5%83%8F%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80%E6%96%B9%E6%B3%95/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

framer-motion使おうとしたらなぜかuseLocationとRouterで躓いた話

経緯 最近Reactを使う機会が増えました。 Reactを夢中で触っているうちに、ふと自分のやってみたかったことの1つを思い出しまして。 別ページを表示するときのあのアニメーションを取り入れてみたい…! (調べたところページトランジションというみたいですね) 今回は簡単にではありますがそれを実践してみようかと。 使用したライブラリ react (v17.0.2) react-router-dom (v5.3.0) framer-motion (v4.1.17) 今回は環境構築等は省きます。 また、複数のページのルーティングを行っている前提で話を進めます。 アニメーションの実装方法 アニメーション自体は以下のようなコードでも実装できます。 Home.tsx import React from "react"; import {motion} from "framer-motion"; const Home = () => { return <motion.div initial={{x:"-100%"}} animate={{x:["-100%","0%"]}} > Home </motion.div> } export default Home; これは、ページを読み込んだ際にHomeという文字を左画面外から元々の位置へ移動させるアニメーションが実行されるコードです。 ただし、この状態ではこのコンポーネントがマウントされる際のアニメーションはオッケーなのですが、アンマウントされる際のアニメーションが実装できていません。 exit処理が使えるらしい。 調べていくうちに、以下の資料からexitの存在を知りました。 この資料によると… animateはマウント時のアニメーションを定義している exitはアンマウント時のアニメーションを定義している アニメーションしたいコンポーネントの親要素として、AnimatePresenceというコンポーネントが必要 AnimatePresenceの子コンポーネントにはkeyを定義しておく必要がある …とのこと。 それっぽく書いてみた とりあえず書いてみないことには始まらないわけで。それっぽくコードを変更。 Home.tsx import React from "react"; import {motion,AnimatePresence} from "framer-motion"; const Home = () => { return <AnimatePresence> <motion.div initial={{x:"-100%"}} animate={{x:["-100%","0%"] exit={{x:["0%","100%"]}}> Home </motion.div> <AnimatePresence> } export default Home; こんな感じ。先ほどのコードに加え、必要なコンポーネントとアンマウント時のアニメーションを定義しました。 …お気づきかもしれませんが、このコード、keyの定義を忘れています。当然エラーが発生し、ここから迷走することに。 keyの定義 これまた色々調べているうちに、子コンポーネントにkeyの定義が必要なことに気づきました。 同時に、keyにはuseLocationなどで取得できるlocationがよく用いられている(?)ことにも気づきます。 まだまだ経験不足ということもあり、keyというものが何かよくわかっていませんでしたが、とりあえず書いてある通り実践してみることに。 locationをkeyに設定した やり方が分かったので、凡例に倣ってコードを変えてみました。 今回は大元のApp.jsを変更。 App.tsx import React from 'react'; import { BrowserRouter as Router, Switch, Route, useLocation, } from "react-router-dom"; import {AnimatePresence} from "framer-motion"; import Navigation from "./components/Navigation"; import Home from "./components/Home/Home"; import About from "./components/About/About"; import Contact from "./components/Contact/Contact"; import "./App.css"; function App() { const location = useLocation(); return ( <Router> <div className="header">Header</div> <Navigation></Navigation> <div> <AnimatePresence exitBeforeEnter> <Switch location={location} key={location.pathname}> <Route exact path="/"> <Home></Home> </Route> <Route exact path="/about"> <About></About> </Route> <Route exact path="/contact"> <Contact></Contact> </Route> </Switch> </AnimatePresence> </div> </Router> ); } export default App; ポイントとしては、 key用のlocation取得にuseLocationを使用 Switchの親コンポーネントにAnimatePresenceを使用 どうやら各コンポーネントにいちいちAnimatePresenceコンポーネントを記述する必要はなく、Switchの親コンポーネントとしてAnimatePresenceを記述すれば問題ないようです。 この時点で、先ほどHome.tsxで記述したAnimatePresenceコンポーネントは消しています。 それでは実行!!!!wktk … なんぞこれ… よく見るCannot read properties of undefinedだけど… エラー自体はよく見るやつ。ただ…なぜこのタイミング? エラーが発生してる場所のコードも問題なさげ。誤字もしてない。 原因が分からんんんんんんん~~~~~~~~~~!!!! 原因を探るべく、またしてもネットの海へダイブ。 あれでもない、これでもない… 2時間くらいこれのためだけにネットサーフィンする羽目になりました。勉強が足りん。 そして… 原因判明 このエラー、どうやらRouterとuseLocation(hooks)の位置が悪かったために起きたエラーのようです。 エラーの起きる条件 Router(BrowserRouter)とhooksが同じコンポーネントファイルにあること hooksがRouter(BrowseRouter)の子コンポーネント以下に設置してあること そんなんしらん…(´・ω・`) というわけで早速修正。 App.tsx import React from 'react'; import { Switch, Route, useLocation, } from "react-router-dom"; import {AnimatePresence} from "framer-motion"; import Navigation from "./components/Navigation"; import Home from "./components/Home/Home"; import About from "./components/About/About"; import Contact from "./components/Contact/Contact"; import "./App.css"; function App() { const location = useLocation(); return ( <div> <div className="header">Header</div> <Navigation></Navigation> <div> <AnimatePresence exitBeforeEnter> <Switch location={location} key={location.pathname}> <Route exact path="/"> <Home></Home> </Route> <Route exact path="/about"> <About></About> </Route> <Route exact path="/contact"> <Contact></Contact> </Route> </Switch> </AnimatePresence> </div> </div> ); } export default App; App.tsxからRouterを削除し… index.tsx import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import { BrowserRouter as Router, } from "react-router-dom"; ReactDOM.render( <React.StrictMode> <Router> <App /> </Router> </React.StrictMode>, document.getElementById('root') ); reportWebVitals(); Appを呼び出しているindex.tsxにRouterを移しました。 無事解決! 動画を見せることはできませんが、無事にマウント時・アンマウント時の両方でアニメーションを実行することができました!これでこれからframer-motionを使って色々遊べそうです。 まとめ 今回はframer-motionを使うときに、useLocationとRouterの使い方で躓いたお話でした。(実はframer-motion自体は間接的に関係しただけで、実際はreact-routerとhooksの問題だったけど。) keyにlocationを設定しようとしたために躓いたエラーだったけど、今後も出てきそうなエラーだったのでそういう意味では良い経験になったかなと。 あのエラー画面苦手だからあんまり見たくないが…(´-ω-`) 以上です。同じようなエラーに直面した時にはhooks等の位置確認もしてみたら幸せになれるかも? ではでは。('ω')ノシ 参考文献 今回参考にさせて頂いた記事をもう一度まとめておきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

分割代入を利用したstate[ ]の更新

const [state, setState] = useState({id:1, firstName:"taro", lastName:"sato"}); const obj = {firstName:"hanako", lastName:"sato"}; const pushFunction = (state) => { setState( [...state, {id:2, ...obj}] ) } // ...state => {id:1, firstName:"taro", lastName:"sato"} // ...arr => firstName:"hanako", lastName:"sato" // id:2, ...arr => id:2, firstName:"hanako", lastName:"sato" // [...state, {id:2, ...obj}] => [{id:1, firstName:"taro", lastName:"sato"}, {id:2, firstName:"hanako", lastName:"sato"}]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

共同開発

インターン生で共同開発をしようという提案が通り、レシピを投稿する簡単なサービスを開発しました。共同開発したサービスの概要、過程、利用したツール等についてまとめていきます。 メンバー 僕を含めた3人(特に分野を決めていませんでしたが、結果的に僕が開発、他2人が設計中心になりました。「特に苦労したこと」) サービス概要 Food Frofessor レシピを投稿し、編集、お気に入り登録、コメントができる基本的なサービスです。 特に苦労したことの経緯や、「共同開発」を経験するといった目的が理由でそこまでハイレベルなサービスにしませんでした。 URL: https://food-professor.herokuapp.com/top (初回のみデータの読み込みに時間がかかります) GitHub: https://github.com/akira-iguchi/FoodProfessor-Backend / https://github.com/akira-iguchi/FoodProfessor-Frontend 使用技術 React (React Hooks, React Router) TypeScript Tailwind CSS Ruby 2.6.6 Rails 6.1.32 MySQL 8.0.23 Heroku Docker/docker-compose Figma Notion drawio VScode 機能一覧 ユーザー機能 ユーザーの新規登録 プロフィール画像の追加 ユーザー情報の編集 レシピ一覧 人気のレシピ トップ3 早くできるレシピ トップ3 最近追加したレシピ レシピ投稿機能 材料、手順を複数追加可能 関連するタグ追加可能 お気に入り機能 レシピのお気に入り登録、解除 お気に入りしたレシピの一覧 検索機能 レシピ名をキーワードに検索 関連するタグ、材料から検索 コメント機能 レシピのコメントの投稿、削除 コメントの一覧 ER図 Notionでタスク管理、設計 Notionという有名なタスク管理ツールでAPI設計、ミーティングメモ、重要な情報等を保存し、タスクを管理しました。 FigmaでUI設計 メンバーの方にFigmaというこれまた有名なデザインツールでUI設計していただき、それを元にFigma to Codeというプラグインで実装していきました(個人的に、このプラグインはそれほど使えなかった)。 環境構築 docker-composeでサービス(rails、react、mysql)をつくろうとしましたが、なんやかんやで1週間以上経過。最終的に1人がdocker-composeファイルをフロントとサーバーサイドで分けて別々で構築したいと提案し(そうじゃないとややこしくてできないと主張)、フロントとサーバーサイドのフォルダに分けて構築しました。 git管理 Fork→cloneしたリポジトリがFork元を追跡するようにし、オリジナルのリモートリポジトリに変更を及ぼすことなく変更をテストすることができるようにしました。 設定方法 ①GitHubから開発したいリポジトリ(オリジナルのプロジェクトのrepo)のページへ飛び、Forkボタンを押します。 ②Forkしたリポジトリ(組織じゃなくて自分のアカウントのレポジトリ)からcloneします。 git clone git@github.com:user_name/app_name.git ③ここで git remote -vを打ってローカルにcloneしたレポジトリがどのように関連づけられているか確認します。 ここで、オリジナルの方がoriginになってたらオリジナルのmasterを変更してしまうことになるので、originのURLを変える必要があります(おそらくそうなってたらOriginalの方からcloneしています)。 $ git remote -v // Forkしたリポジトリのみがoriginとして表示されます origin git@github.com:user_name/app_name.git (fetch) origin git@github.com:user_name/app_name.git (push) // もしOriginalの方をoriginとして登録されていたら $ git remote set-url origin YOUR_FORK_REPO_URL ④Fork元のリポジトリをローカルのリポジトリに関連づけます(URLを追加する) $ git remote set-url upstream ORIGINAL_REPO_URL ⑤upstreamとしてURLが追加されているか確認 $ git remote -v origin git@github.com:user_name/app_name.git (fetch) origin git@github.com:user_name/app_name.git (push) upstream git@github.com:team/app_name.git (fetch) upstream git@github.com:team/app_name.git (push) ⑥(upstreamとしてOriginalのリポジトリをURLに登録した後) git fetch upstream でリモートにあるOriginalの最新の変更状態をローカルに持ってきます。 ⑦git merge upstream/master で、自分のいるローカルのブランチにOriginalのローカルリポジトリ(upstream)のmasterブランチの変更分を適用させます。 ⑧ローカルで開発を進める。 個人的おすすめは git add 前にOriginalの変更分をfetchしておくこと git stash → git fetch && merge → git stash apply → git add && commit && push ローカルのoriginリポジトリ(Fork先の個人用リポ)へpushを続けていれば、組織のOriginalブランチに影響を及ぼさず、個人レポジトリで開発進められます。 特に苦労したこと 設計、環境構築までは空いた時間ながらもメンバーと協力し合い順調に進んだのですが、開発を進めていくうちに就職活動等でメンバーの方々が忙しくなり、まともな開発時間を有するのは僕だけになりました。このとき僕も共同開発後の予定を立てており、1人で悠々と作業を進める時間はありませんでした。このままでは、計画も意味をなくし、共同開発が断念される恐れがありました。 どうやって乗り越えたか それでも何とかサービスを完成させてデプロイまで終わらせたいと考えた僕は、メンバーと話し合い、機能の削減、メンバーの必要最低限の作業などを提案し、その後の開発は僕が中心となって進めました。そして、実装したい機能を妥協しながらも、許容範囲の期間でデプロイまで終わらせることができました。 まとめ 設計やgit管理など、個人開発とは違った実務に近い良い経験ができました。また、ほぼ無知だった僕にNotionなどのツールや専門知識などをお教えくださり、メンバーには感謝の気持ちでいっぱいです。優秀なメンバーの方々に負けないようこれからも頑張っていこうと思います。 気がかりとしては、まともなissue管理ができなかったので、今後は複数人での開発に向けてissueの扱いを学んでおきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む