React注記を使用してWebページのパフォーマンスを向上させる(feat.lighthouse)
56995 ワード
ChawChawプロジェクトの反応注記の適用
反応には記録という機能があります.React.memo
, useCallback
, useMemo
この3つの機能は、構成部品の再実行を防止し、複数回の実行時間を短縮し、再レンダリングを最小限に抑えることができます.
React.memo
この機能は、親コンポーネントに適しているほど良いです.
デフォルトでは、ステータス変数として定義された変数が変更されると、リアクターは構成部品を再実行し、変更されたステータスを構成部品に反映します.
親構成部品でこの手順を実行すると、すべての依存する子構成部品が再実行されます.
したがって、サブコンポーネントで親コンポーネントから継承されたpropsが変更されていない場合は、再実行する必要はありません.
これらの概念において、React.memo
は、対応する要素を取り囲む.また親からもらった道具に変更はありませんか.
浅い比較で比較する.
このような簡単な比較を行うために、useCallback
、useMemo
が使用される.
詳細な操作手順
この時は使わないでください。
上記の2つのコードでは、PostModelはほとんどpropsをサブコンポーネントに渡します.すなわち、サブエレメントの立場では、PostModal
が変化すると、サブエレメントに伝達されるprops
が毎回変化する.これで道具を比較する必要がなくなります.意味のない単純な比較演算を実行します.こんな時はいらない.
PostModal.tsxconst PostModal: React.FC<PostModalProps> = (props) => {
const now = new Date();
const dateArr = props.regDate.substring(0, 10).split("-");
const stDate = new Date(
Number(dateArr[0]),
Number(dateArr[1]),
Number(dateArr[2])
);
const endDate = new Date(
now.getFullYear(),
now.getMonth() + 1,
now.getDate()
);
const pastDays =
(endDate.getTime() - stDate.getTime()) / (1000 * 60 * 60 * 24);
const repCountry = props.repCountry;
const repLanguage = LocaleLanguage[props.repLanguage] || "";
const repHopeLanguage = LocaleLanguage[props.repHopeLanguage] || "";
const country = props.country;
const language = useMemo(() => {
return props.language.map((item) => LocaleLanguage[item] || "");
}, [props.language]);
const hopeLanguage = useMemo(() => {
return props.hopeLanguage.map((item) => LocaleLanguage[item] || "");
}, [props.hopeLanguage]);
return (
<PostModalBox>
<PostModalImage src={`${props.imageUrl}`} />
<PostUserName>{props.name}</PostUserName>
<PostModalActive id={props.id} isLike={props.isLike} />
<PostModalInfoList
title="I am from"
values={country}
mainValue={repCountry}
/>
<PostModalInfoList
title="I can speak"
values={language}
mainValue={repLanguage}
/>
<PostModalInfoList
title="I want to speak"
values={hopeLanguage}
mainValue={repHopeLanguage}
/>
<PostModalContent content={props.content} />
<PostModalSocialList
title="Contact to me"
faceBookUrl={props.facebookUrl}
instagramUrl={props.instagramUrl}
/>
<PostModalInfo
regDate={String(pastDays)}
views={props.views}
likes={props.likes}
/>
</PostModalBox>
);
};
export default React.memo(PostModal);
使用
LikeAlarm.tsxconst MLikeAlarm: React.FC = () => {
const newLikes = useAppSelector((state) => state.chat.newLikes);
const alarmlikeMessages = newLikes.map((item) => {
return (
<AlarmChatBox key={item.regDate + item.name}>
<ChatBox
imageUrl={`/Layout/heart.png`}
regDate={item.regDate}
sender={item.likeType}
context={`${item.name}님이 ${item.likeType} 하셨습니다.`.substring(
0,
20
)}
type={LIKEALARM_TYPE}
/>
</AlarmChatBox>
);
});
return (
<PushAlarmBox>
{newLikes.length > 0 ? (
alarmlikeMessages
) : (
<EmptyAlarm title="No new likes Messages" />
)}
</PushAlarmBox>
);
};
const LikeAlarm = React.memo(MLikeAlarm);
export { LikeAlarm };
上のコードはprops
で、何も受け取りません.つまり、親構成部品が再実行されても、再実行する必要はありません.再実行しても同じ運転が繰り返されるからです.
この場合は行動しなければならない.memoを使用して、親構成部品が再実行時に再実行されないことを浅い比較で確認します.
useCallback
useCallback
は、関数の参照値を格納します.デフォルトでは、JavaScriptは、関数もオブジェクトであるため、参照値を格納します.したがって、構成部品が再実行されると、関数の参照値が変更されます.参照値を注記するときに構成部品の再実行時にdeps配列の値が変更されない場合は、新しい関数は作成されず、既存の参照値を読み込み、関数を実行します.
この時に使いましょう。
上記のように、React.memo
は浅い比較を行う.関数をサブエレメントとしてprops
に入れると、その関数は毎回再実行されて新しい参照値を持つので、同じ関数でも新しい参照値を持つ新しい関数としてサブエレメントに渡されます.React.memo
を用いて浅い比較を行うサブエレメントでは、不変の関数であるため、再実行する必要がある.この場合、useCallback
を使用できます.
ChatRoom.tsx const handleChangeInput: ChangeEventHandler<HTMLTextAreaElement> =
useCallback((e) => {
setMessage(e.target.value);
}, []);
const scrollToBottom = useCallback(() => {
if (!chatMessageBox.current) return;
chatMessageBox.current.scrollIntoView({
behavior: "auto",
block: "end",
inline: "nearest",
});
}, []);
useEffect(() => {
scrollToBottom();
}, [mainChatMessages.length, scrollToBottom]);
return (
<Outline>
<Inner>
<ChatRoomHeader
selectLanguage={selectLanguage}
setSelectLanguage={setSelectLanguage}
/>
{isViewChatList ? (
<ChatListWrapper>
<ChatList />
</ChatListWrapper>
) : (
<>
<MessageContainer>{messageBoxContent}</MessageContainer>
<MessageInput
onChange={handleChangeInput}
sendMessage={sendMessage}
value={message}
/>
</>
)}
</Inner>
</Outline>
);
上記のコードから見ると、MessageInput
およびprops
を超え、handleChangeInput
を超えている.useCallbackを使用して、関数値をMessageInput構成部品に格納し、再実行のたびに実行しないようにします.
また、useEffect()
においても同様である.useEffectで関数を使用するにはdepsに関数を追加する必要があります.関数が毎回同じ関数である場合は、useEffect
のコールバック関数が余分に再実行されないように関数値を保存する必要があります.
このような場合、useCallbackで囲まれた関数で関数を使用すると、同じ理由で中の関数をuseCallbackで囲まれます.
こんな時は使わないでください。
関数内のパラメータが毎回変化する場合、いずれにしてもパラメータのせいで関数が再生成されるので保存する必要はありません.いずれにしても、再生後に捨てる場合は不要です.
useMemo
オブジェクトには参照値があるため、毎回新しい値があります.
ChangeLanguageDropDown.tsxconst MChangeLanguageDropDown: React.FC<ChangeLanguageDropDownProps> = (
props
) => {
const { bodyBackgroundColor, bodyFontColor } = useContext(ThemeContext);
const initialValue = LanguageLocale[props.selectLanguage[0]].toUpperCase();
const options = useMemo(() => ["Korean", ...Object.keys(LanguageLocale)], []);
return (
<ChangeLanguageDropDownBox>
<DropDown
fontWeight="600"
fontSize="1em"
width="110px"
height="30px"
options={options}
initialValue={initialValue}
setValues={props.setSelectLanguage}
value={initialValue}
index={0}
type={NOMAL_TYPE}
backgroundColor={bodyBackgroundColor}
color={bodyFontColor}
>
<ImEarth />
</DropDown>
</ChangeLanguageDropDownBox>
);
};
const ChangeLanguageDropDown = React.memo(MChangeLanguageDropDown);
上のコードを見ると、optionsのたびに一定の値があります.別の値に依存して変更される値でもないので、毎回新しい参照値を作成する必要はありません.
したがって、userMemoを使用してオブジェクトを囲み、参照値を下げます.これにより、サブエレメントから受信すると、React.memo
による運転再開を防止することができる.
LightHouseによるWebパフォーマンスの向上
Performance
性能の向上を測定するためにクロムを用いたLightHouse
.このセクションでは、パフォーマンスは6つの異なる基準で測定されます.
冗長ではなく含蓄として定義し、ユーザーが表示するレンダリング時間を測定します.注釈をうまく適用すれば,性能の向上はこの部分で測定される.
Accessibility
この部分で多くの改善をした.
視覚障害者がウェブページを使用するときは、ページリーダーを使用します.このとき,リーダーがこれらのラベルを正しく説明できないと,アクセス性の低下として現れる.
input、labelをtextarea tagに追加
Li,ulラベル接続
button tagにtextがない場合はaria-labelまたはtextを追加します
などなど.
¥背景色とテキストのコントラストを強調し、この部分は信頼できないようです.オレンジと白は区別しやすいです
Best Practices
すべてのエラーコンソールを削除
@font-face:font-display swapを追加
const PostModal: React.FC<PostModalProps> = (props) => {
const now = new Date();
const dateArr = props.regDate.substring(0, 10).split("-");
const stDate = new Date(
Number(dateArr[0]),
Number(dateArr[1]),
Number(dateArr[2])
);
const endDate = new Date(
now.getFullYear(),
now.getMonth() + 1,
now.getDate()
);
const pastDays =
(endDate.getTime() - stDate.getTime()) / (1000 * 60 * 60 * 24);
const repCountry = props.repCountry;
const repLanguage = LocaleLanguage[props.repLanguage] || "";
const repHopeLanguage = LocaleLanguage[props.repHopeLanguage] || "";
const country = props.country;
const language = useMemo(() => {
return props.language.map((item) => LocaleLanguage[item] || "");
}, [props.language]);
const hopeLanguage = useMemo(() => {
return props.hopeLanguage.map((item) => LocaleLanguage[item] || "");
}, [props.hopeLanguage]);
return (
<PostModalBox>
<PostModalImage src={`${props.imageUrl}`} />
<PostUserName>{props.name}</PostUserName>
<PostModalActive id={props.id} isLike={props.isLike} />
<PostModalInfoList
title="I am from"
values={country}
mainValue={repCountry}
/>
<PostModalInfoList
title="I can speak"
values={language}
mainValue={repLanguage}
/>
<PostModalInfoList
title="I want to speak"
values={hopeLanguage}
mainValue={repHopeLanguage}
/>
<PostModalContent content={props.content} />
<PostModalSocialList
title="Contact to me"
faceBookUrl={props.facebookUrl}
instagramUrl={props.instagramUrl}
/>
<PostModalInfo
regDate={String(pastDays)}
views={props.views}
likes={props.likes}
/>
</PostModalBox>
);
};
export default React.memo(PostModal);
const MLikeAlarm: React.FC = () => {
const newLikes = useAppSelector((state) => state.chat.newLikes);
const alarmlikeMessages = newLikes.map((item) => {
return (
<AlarmChatBox key={item.regDate + item.name}>
<ChatBox
imageUrl={`/Layout/heart.png`}
regDate={item.regDate}
sender={item.likeType}
context={`${item.name}님이 ${item.likeType} 하셨습니다.`.substring(
0,
20
)}
type={LIKEALARM_TYPE}
/>
</AlarmChatBox>
);
});
return (
<PushAlarmBox>
{newLikes.length > 0 ? (
alarmlikeMessages
) : (
<EmptyAlarm title="No new likes Messages" />
)}
</PushAlarmBox>
);
};
const LikeAlarm = React.memo(MLikeAlarm);
export { LikeAlarm };
const handleChangeInput: ChangeEventHandler<HTMLTextAreaElement> =
useCallback((e) => {
setMessage(e.target.value);
}, []);
const scrollToBottom = useCallback(() => {
if (!chatMessageBox.current) return;
chatMessageBox.current.scrollIntoView({
behavior: "auto",
block: "end",
inline: "nearest",
});
}, []);
useEffect(() => {
scrollToBottom();
}, [mainChatMessages.length, scrollToBottom]);
return (
<Outline>
<Inner>
<ChatRoomHeader
selectLanguage={selectLanguage}
setSelectLanguage={setSelectLanguage}
/>
{isViewChatList ? (
<ChatListWrapper>
<ChatList />
</ChatListWrapper>
) : (
<>
<MessageContainer>{messageBoxContent}</MessageContainer>
<MessageInput
onChange={handleChangeInput}
sendMessage={sendMessage}
value={message}
/>
</>
)}
</Inner>
</Outline>
);
const MChangeLanguageDropDown: React.FC<ChangeLanguageDropDownProps> = (
props
) => {
const { bodyBackgroundColor, bodyFontColor } = useContext(ThemeContext);
const initialValue = LanguageLocale[props.selectLanguage[0]].toUpperCase();
const options = useMemo(() => ["Korean", ...Object.keys(LanguageLocale)], []);
return (
<ChangeLanguageDropDownBox>
<DropDown
fontWeight="600"
fontSize="1em"
width="110px"
height="30px"
options={options}
initialValue={initialValue}
setValues={props.setSelectLanguage}
value={initialValue}
index={0}
type={NOMAL_TYPE}
backgroundColor={bodyBackgroundColor}
color={bodyFontColor}
>
<ImEarth />
</DropDown>
</ChangeLanguageDropDownBox>
);
};
const ChangeLanguageDropDown = React.memo(MChangeLanguageDropDown);
Performance
性能の向上を測定するためにクロムを用いた
LightHouse
.このセクションでは、パフォーマンスは6つの異なる基準で測定されます.冗長ではなく含蓄として定義し、ユーザーが表示するレンダリング時間を測定します.注釈をうまく適用すれば,性能の向上はこの部分で測定される.
Accessibility
この部分で多くの改善をした.
視覚障害者がウェブページを使用するときは、ページリーダーを使用します.このとき,リーダーがこれらのラベルを正しく説明できないと,アクセス性の低下として現れる.
input、labelをtextarea tagに追加
Li,ulラベル接続
button tagにtextがない場合はaria-labelまたはtextを追加します
などなど.
¥背景色とテキストのコントラストを強調し、この部分は信頼できないようです.オレンジと白は区別しやすいです
Best Practices
すべてのエラーコンソールを削除
@font-face:font-display swapを追加
アンインストールアクティビティを使用したことがなく、なぜいつも交換させてくれたのか分かりません.
SEO
title, description, opengraph, twitter, ...
_app.tsx
<DefaultSeo
title={"ChawChaw 언어를 교환합시다.🗣"}
description={"대학내 교환학생 언어교환 채팅 어플리케이션입니다."}
canonical="https://www.chawchaw.vercel.app"
openGraph={{
type: "website",
locale: "en_IE",
title: "ChawChaw 언어를 교환합시다.🗣",
description: "대학내 교환학생 언어교환 채팅 어플리케이션입니다.",
images: [
{
url: "https://i.ibb.co/m0NY7yQ/image.jpg",
width: 800,
height: 600,
alt: "ChawChaw 소개 이미지",
},
],
url: "https://www.chawchaw.vercel.app",
site_name: "ChawChaw",
}}
twitter={{
handle: "@chawchawTwitter",
site: "chawchaw.vercel.app",
cardType: "summary",
}}
additionalLinkTags={[
{
type: "image/png",
sizes: "32x32",
href: "/Layout/chaw.png",
rel: "icon",
},
]}
additionalMetaTags={[
{
name: "viewport",
content:
"viewport-fit=cover, width=device-width, initial-scale=1",
},
]}
/>
<Component {...pageProps} />
_document.tsx<Html lang="kr">
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@200;300;400;600;700;900&display=swap"
rel="stylesheet"
/>
<link rel="canonical" href="https://www.chawchaw.vercel.app" />
</Head>
<body>
<div id="root">
<Main />
<NextScript />
</div>
<div id="notification"></div>
</body>
</Html>
LightHouse測定結果
/home
BeforeAfter
/account/login
BeforeAfter
/account/signup
BeforeAfter
/account/signup/webMailAuth
BeforeAfter
/account/profile
BeforeAfter
/account/setting
BeforeAfter
/chat
BeforeAfter
/post
BeforeAfter
/manage/users
BeforeAfter
/manage/users/detail
BeforeAfter
/manage/statistics
BeforeAfter
ぐつぐつ
4026->4282平均6.36%上昇!
期待されるパフォーマンスの改善点は次のとおりです。
Reference
この問題について(React注記を使用してWebページのパフォーマンスを向上させる(feat.lighthouse)), 我々は、より多くの情報をここで見つけました https://velog.io/@doodream/React-메모제이션을-이용한-웹-페이지-성능개선feat.-lighthouseテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol