20210621のReactに関する記事は6件です。

JavaScript 関数をキャッシュする(Reactとかで使えるかも)

React でJSX内に、アロー関数式を書いたりしていると、毎度呼び出すときにレンダリングが走っちゃうんじゃないのかな、 ということを回避するための仕組みの試作です。 const _cashFuncMap = new Map(); const cashFunc = (func) => { const strFunc = func.toString(); let result = _cashFuncMap.get(strFunc); if (result === undefined) { result = func; _cashFuncMap.set(strFunc, func) } return result; }; const f1 = () => 'test'; console.log(f1()); // "test" const f2 = cashFunc(f1); console.log(f2()); // "test" console.log(f1 === f2); // true const cf = cashFunc; const f3 = cf( (a) => a + a ) console.log(f3('ABC')); // "ABCABC" const f4 = cf( (a) => a + a ) console.log(f4('DEF')); // "DEFDEF" console.log(f3 === f4); // true これで、文字列として変換した形が同じ関数なら、アロー関数式を動的に書いたとしてもcf(関数)の形式で書いておけば、キャッシュされた値によって同値が返るので再レンダリングされない、みたいな。 でも、Reactの再レンダリングの仕組みよりも、functionのtoStringしてMapで値を持ってくるほうが遅いんじゃないだろうか、みたいな。検証してないからしらんけど。 動的に関数式を生成しないけど、即時でかけるような専用の構文がほしい。あるいは、React側が再レンダリングしないように対応してくれるようにならないかと思ったり。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Next.js】Reactでスクロールを検知する

コード scroll.jsx import React, {useState, useEffect} from 'react' const Scroll = () => { const [scrollY, setScrollY] = useState(0) const handleScroll = () => { setScrollY(window.scrollY) } useEffect(()=> { window.addEventListener('scroll', handleScroll ) }, []) return ( <> { scrollY } </> ) } export default Scroll 解説 window.addEventListener('scroll', handleScroll ) ここでイベントリッスンさせて、 const handleScroll = () => { setScrollY(window.scrollY) } 関数handleScrollを呼び出すだけ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactアプリケーションを高速化するための方法

Reactアプリケーションを高速化するための方法 結論から 無駄な再レンダリングを発生させない 処理しないこと 高速化とは処理しないことです 矛盾しているように思えますが、処理が減ればアプリケーションは高速化します Reactの処理を減らすためには 再レンダリングをしないことです もちろん完全に再レンダリング無しというのは不可能なので、いかにそれを減らしていくかが重要です 再レンダリングの妥当性 妥当な再レンダリング コンポーネントのstateに変化があって自身の挙動を変更しなければならないとしたら、その再レンダリングは妥当です 妥当ではない再レンダリング コンポーネント自身がそのstateを必要としておらず、下位に配るためstateを保持しているとしたら、その際レンダリングは妥当ではありません そういう構造を作ってしまえば、配下にいる全コンポーネントがstateと無関係に再レンダリングされます。 何故、こんな構造がまかり通ってしまうのか useStateが三つの機能を一つに集約してしまったのが原因です。詳しくは[React]useStateによるstate管理の問題点とその解決方法を模索した結果、3つの機能を分離するに至った話を参照してください。 解決方法 上位コンポーネントで下位に配るためのstateを保持しない 無駄なstateの保持、これが諸悪の根源です とにかく自身で使用しないstateを保持するのをやめる必要があります 上位コンポーネントでstateを保持しないためには state管理ライブラリを使用する ReduxやContextAPIを使用すれば、親コンポーネントを経由せずともstateを配ることが出来ます ただし、以下の欠点があります stateのスコープがグローバルになってしまい、特定のコンポーネントグループ内で閉じさせるのが困難 仕組みを作成するコストが大きく、気軽に利用しにくい state管理をコンポーネントグループでローカル化する 特定コンポーネント間で閉じられたstate管理が出来て、簡単に利用出来れば問題は解決です ということで作りました stateの作成、更新、取得を分離させたライブラリ @react-libraries/use-local-state コンポーネント間でイベント通知を行うライブラリ @react-libraries/use-local-event 両方とも、stateやeventを扱うための識別ハンドルを上位コンポーネントで作成し、それを下位コンポーネントで使用する仕組みです ハンドルを作成した上位コンポーネントはstateの更新やevent通知の影響を受けないので、再レンダリングはされません state管理のグループローカル化の具体例 Sample1 特に対策を打たない、通常の書き方 Inputコンポーネントにボタンが配置されており、押すごとにstateが+1されます Test1とTest2はstateを受け取って、値を1万回表示します Test3はstateとは無関係にTest3を1万回表示します import React, { useState } from 'react'; const count = 10000; const Test1 = ({ value }: { value: number }) => ( <div> <div>Test1</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> ); const Test2 = ({ value }: { value: number }) => ( <div> <div>Test2</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> ); const Test3 = () => ( <div> <div>Test3</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>Test3</div> ))} </div> ); const Input = ({ setValue }: { setValue: React.Dispatch<React.SetStateAction<number>> }) => ( <button onClick={() => setValue((v) => v + 1)}>+1</button> ); const App = () => { const [value, setValue] = useState(0); return ( <> <div>通常</div> <Input setValue={setValue} /> <hr /> <div style={{ display: 'flex' }}> <Test1 value={value} /> <Test2 value={value} /> <Test3 /> </div> </> ); }; export default App; Sample2 memo化 Sample1をmemo化したものです import React, { memo, useState } from 'react'; const count = 10000; const Test1 = memo(({ value }: { value: number }) => ( <div> <div>Test1</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> )); const Test2 = memo(({ value }: { value: number }) => ( <div> <div>Test2</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> )); const Test3 = memo(() => ( <div> <div>Test3</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>Test3</div> ))} </div> )); const Input = memo(({ setValue }: { setValue: React.Dispatch<React.SetStateAction<number>> }) => ( <button onClick={() => setValue((v) => v + 1)}>+1</button> )); const App = () => { const [value, setValue] = useState(0); return ( <> <div>memo化</div> <Input setValue={setValue} /> <hr /> <div style={{ display: 'flex' }}> <Test1 value={value} /> <Test2 value={value} /> <Test3 /> </div> </> ); }; export default App; Sample3 グループローカル化 useLocalStateによって、上位コンポーネントの再レンダリングを行わない書き方になっています import { LocalState, mutateLocalState, useLocalState, useLocalStateCreate, } from '@react-libraries/use-local-state'; import React from 'react'; const count = 10000; const Test1 = ({ state }: { state: LocalState<number> }) => { const [value] = useLocalState(state); return ( <div> <div>Test1</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> ); }; const Test2 = ({ state }: { state: LocalState<number> }) => { const [value] = useLocalState(state); return ( <div> <div>Test2</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>{value}</div> ))} </div> ); }; const Test3 = () => ( <div> <div>Test3</div> {new Array(count).fill(0).map((_, index) => ( <div key={index}>Test3</div> ))} </div> ); const Input = ({ state }: { state: LocalState<number> }) => ( <button onClick={() => mutateLocalState(state, (v) => v + 1)}>+1</button> ); const App = () => { const state = useLocalStateCreate(0); return ( <> <div>localState</div> <Input state={state} /> <hr /> <div style={{ display: 'flex' }}> <Test1 state={state} /> <Test2 state={state} /> <Test3 /> </div> </> ); }; export default App; 結果の検証 ボタンを押してstateを変化させたときのprofile結果です Render durationがレンダリング時間です Sample1の結果 レンダリング時間 228.2ms 特に何も対応していないので、全てのコンポーネントが再レンダリングされています 当然、一番遅いです Sample2の結果 レンダリング時間 162.2ms memo化によってTest3の更新はスキップされていますが、Appは再レンダリングされています 何もしないよりは速度が向上していますが、まだ無駄が残っています Sample3の結果 レンダリング時間 95.2ms 本当に更新が必要なコンポーネントのみ再レンダリングされています 処理を行う内容は必要最低限です まとめ Reactアプリケーションを高速化させるためには、更新の必要が無いコンポーネントを再レンダリングしないことです。そのためにはとにかく上位コンポーネントに余計なstateを持たせないというのが基本です 今回は効率的なstate管理のために、stateをグループで閉じるためのライブラリを使用しました。その他にstateを使わずにevventのみ配るライブラリもあるので、次回はそちらも紹介したいと思います
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactで配列のメソッドを使用する際に注意すること(push)

Reactで配列のメソッドを使用する際に注意すること(push) 自分がReactを勉強し始めて、基本的なことを忘れていたために行き詰まった点をこちらで紹介させていただきます。 ほとんど備忘録のような感覚で書かせていただいているので、細かな間違いがあるかもしれません。 今回は、大抵のプログラミング言語で使用される、配列メソッドpushを使用した際に基本的な部分で行き詰まった点について紹介します。 pushの戻り値は、配列ではなくpush後の配列の要素数である 自分はこれを忘れていて、Reactの勉強をしているときに少し悩まされました。 例えば、ある配列 const Arry = new Array(); に対して、さらに要素を追加したいとします。 そして、その配列の要素を別の変数に記憶させたいとき、自分はついつい次のように書いてしまいました。 const newArry = Array.push( "追加したい要素" ); この場合、タイトルにもある通り、pushは(要素を追加した後の)配列の要素数を戻り値として返すので、newArryは配列ではなく整数値になります。 それに気づかないままnewArryを配列のつもりで使用していくと、エラーが発生してしまいます。 なので、push後の配列の要素を別の配列変数に記憶したい場合、Reactでは次のように書くことができます。 const newArry = [...Arry, ("追加したい要素")]; この ...Arry は、JavaScriptで使用可能なスプレッド構文と呼ばれる記述法で、その場で配列の要素を展開できます。 まとめ 今回のpushの使い方については、正直Reactは関係ありませんが、自分がReactを使っていて躓いたので、備忘録としてReact関連の記事にさせていただきました。 また、スプレッド構文を用いて配列の要素を変更する手順は、Reactで何度も使うと思うので、参考程度に話させていただきました。 React関係なく、プログラミングで似たような点で躓いていらっしゃる方がおられれば、参考にしていただければ幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React + Material UIで動的アイコンを表示する

Material UIのアイコンを入力とか、データループとかから動的に作成したかった やりかた サイドバーのデータを表示する例 import * as Icons from '@material-ui/icons/' const datas = [ { icon: 'Home', title: 'ホーム', to: '/home', } ] function Sidebar(){ return ( <ul> {datas.map((data, index) => ( <li>{React.createElement(Icons[data.icon])}</li> ))} </ul> ) } import * as Icons from '@material-ui/icons/'で モジュールのコンテンツすべてをインポートしています。参考 あとは、データをループしてReact.createElementでReact要素で対象のアイコンを作成しています
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

'--jsx' フラグが指定されていないと、JSX を使用できません。のエラーの解決方法

create-react-appをつかって実行(npm start)しようとした時に上記のようなエラーが出た。 tsconfig.jsonの"jsx": "react-jsx"となっていたところを、```"jsx": "react"と直したらエラーがなくなった。 参考にしたサイト https://terrblog.com/reacttypescript/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む