วิธีใช้ React.memo เพื่อเพิ่มประสิทธิภาพ
ฉันสร้างเกมหมากรุกโดยใช้ React frontend ในขั้นต้นการเคลื่อนไหวใด ๆ จะถูกนำไปใช้อย่างทันทีทันใด แต่หลังจากเพิ่มคุณสมบัติพิเศษเช่นการเปลี่ยนพื้นหลังของส่วนหัวเพื่อให้สะท้อนถึงการเปิดใช้งาน (พื้นหลังสีขาวหรือสีดำขึ้นอยู่กับว่าการเคลื่อนไหวของสีขาว) และคุณสมบัติอื่น ๆ ที่คล้ายกันแอปของฉันช้าลงอย่างเห็นได้ชัด ฉันสงสัยว่ามันเป็นประเภทของคำสั่ง if -
const Details = props => {
console.log(props.status);
let [backGround, setBackGround] = useState("w details")
const history = useHistory();
if (props.status.white && backGround === "bl details"){
setBackGround("w details")
} else if (!props.status.white && backGround === "w details"){
setBackGround("bl details")
}
ที่ต้องรับผิดชอบเพราะ console.log การพิมพ์อุปกรณ์ประกอบฉากจะพิมพ์คำสั่ง 8 ครั้งต่อการเคลื่อนไหว (แต่เดิมเป็นสองครั้ง)
ฉันใช้ส่วนประกอบที่ใช้งานได้มากกว่าคลาสและการวิจัยเกี่ยวกับการเพิ่มประสิทธิภาพทำให้ฉันได้แนวทางแก้ไขต่อไปนี้
React Hooks - ฉันจะติดตั้ง shouldComponentUpdate ได้อย่างไร
ฉันควรห่อส่วนประกอบทั้งหมดของฉันด้วย React.memo () หากไม่ได้คาดหวังอุปกรณ์ประกอบฉากใด ๆ
ใช้ shouldComponentUpdate กับ React Hooks อย่างไร?
ทั้งหมดชี้ไปที่กรณีง่ายๆReact.memoแต่เห็นได้ชัดว่าฉันพลาดอะไรบางอย่างไปเพราะเมื่อฉันพยายามที่จะใช้มันสิ่งที่ฉันได้รับคือ 'อุปกรณ์ประกอบฉาก' มากมายเหลือเฟือที่ไม่ได้กำหนดข้อผิดพลาด (หนึ่งข้อสำหรับแต่ละครั้งที่ฉันใช้อุปกรณ์ประกอบฉากซึ่งมีจำนวนมาก)
รายละเอียด jsx
import React, { useState } from 'react';
import "../App.css"
import DataService from '../service/DataService';
import { useHistory } from 'react-router-dom';
let [backGround, setBackGround] = useState("w details")
const Details = React.memo(props => {if (props.status.white){setBackGround("w details")} else {setBackGround("bl details")}}, (prevProps, props) => prevProps.white === props.white); {
console.log(props.status);
const history = useHistory();
const undo = () => {
DataService.undo()
.then(res => {
console.log(res);
props.setTheBoard(res.data);
props.changeTurn();
})
.catch(err => {
console.log(err);
window.alert(err.response.data.errMessage)
})
}
const restart = () => {
DataService.restartGame()
.then(res => {
console.log(res);
props.setTheBoard(res.data);
props.changeTurn(true);
})
.catch(err => {
console.log(err);
window.alert(err.response.data.errMessage)
})
}
const newGame = () => {
history.push('/');
}
return (
<div className={backGround} >
{props.status.active ? <h2>It is {props.status.playerName}'s turn</h2> :
<div>
<h1 className="check">Game Over!</h1>
<button className="tooltip" onClick={restart}>RESTART<span className="tooltiptext">Play another game vs the same opponent</span></button>
<button className="tooltip" onClick={newGame}>NEW GAME<span className="tooltiptext">Play a game vs a different opponent</span></button>
</div>}
{props.status.active &&
<div>
{props.isMove ? <button className="detailButtons" onClick={props.specialMove}>Special Move</button> : <button className="detailButtons" onClick={() => props.endTheGame(true)}>Forfeit</button> }
{props.isMove ? <button className="detailButtons" onClick={props.unselect}>Unselect Piece</button> : <button className="detailButtons" onClick={() => props.endTheGame(false)}>Draw</button> }
{props.isMove ? <button className="detailButtons">Toggle Sidebar</button> : props.undo && <button className="detailButtons" onClick={() => undo()}>Undo</button> }
{props.status.check && <h1 className="check">You must move out of check!</h1>}
</div> }
</div>
);
}
export default Details;
เนื่องจากอุปกรณ์ประกอบฉากในส่วนประกอบนี้จะเปลี่ยนเฉพาะเมื่อเทิร์นเปลี่ยนไป (props.status.white) ฉันคิดว่านี่น่าจะเป็นจุดที่ดีในการพยายามลดการแสดงผลซ้ำที่ไม่จำเป็น แต่วิธีแก้ปัญหาทั้งหมดที่ฉันเห็นว่ามันง่ายมาก มันเป็นไปไม่ได้ที่จะใช้ React.memo เมื่อมีการใช้อุปกรณ์ประกอบฉากเช่นนี้อย่างแพร่หลาย?
ฉันจะเพิ่มประสิทธิภาพในขณะที่ยังสามารถเข้าถึงอุปกรณ์ประกอบฉากได้อย่างไร
คำตอบ
อันดับแรกสิ่งที่คุณต้องคำนึงถึงเกี่ยวกับการทดสอบประสิทธิภาพในส่วนหน้าโดยทั่วไป
คุณจะไม่เปิด devtools ทิ้งไว้ในขณะที่คุณกำลังตรวจสอบประสิทธิภาพกิจกรรมต่างๆใน devtools ลดประสิทธิภาพของแอปของคุณได้มาก
ประการที่สองทั้งสองอย่างuseMemoและuseCallbackจะไม่ให้การปรับปรุงประสิทธิภาพใด ๆ แก่คุณหากคุณไม่ได้แสดงผลอย่างละเอียดถี่ถ้วนการแสดงผลอุปกรณ์ประกอบฉากที่เป็นไปได้จะถูกแสดงผลก่อนหน้านี้และที่สำคัญที่สุดหากคุณไม่ได้แสดงส่วนประกอบที่กำหนดเองอื่น ๆ ภายในองค์ประกอบที่กำหนดเองของคุณคุณอาจจะไม่ทำ ต้องใช้ตะขอเหล่านั้นด้วย
ดังนั้นเราควรใช้สถานการณ์ใดuseCallbackและuseMemoเพื่อปรับปรุงประสิทธิภาพ
ก่อนจะตอบคุณควรทราบความแตกต่างระหว่างประเภทค่าและประเภทการอ้างอิง
ประเภทค่าไม่เปลี่ยนรูปดังนั้นคุณสามารถกำหนดแก้ไขและใช้งานได้อย่างปลอดภัยโดยไม่ต้องกังวลกับความเป็นเจ้าของและตัวเก็บขยะ
ประเภทตัวอักษรดั้งเดิมใน JS เป็นประเภทค่า:
let a = "Hello"
let b = a
// from here, b doesn't own a reference, because a is a value type
let c = new String("Hello")
let d = c
// now d owns c reference because c was initialized as an instance of String class
นี่เป็นตัวอย่างง่ายๆของการสร้างสตริงเดียวกันโดยใช้สองวิธีที่แตกต่างกัน
อย่างแรกคือการสร้างสตริงโดยใช้สตริงตามตัวอักษร ประการที่สองโดยใช้อินสแตนซ์ของคลาส String
ถ้าเราทำอะไรแบบนั้น:
a === b // true
===เปรียบเทียบค่าของaกับค่าbใน
อย่างไรก็ตามสิ่งที่แตกต่างเกิดขึ้นเมื่อเราทำสิ่งนั้น:
c === d // true
นอกจากนี้ยังกลับมาtrueแต่===การทำงานที่แตกต่างกันที่นี่แทนค่าเปรียบเทียบก็เปรียบเทียบอ้างอิงของ c เป็นอย่างเคร่งครัดเท่ากับอ้างอิงง เราไม่สามารถเปรียบเทียบได้ว่าค่าของcนั้นเท่ากับค่าของการdใช้===ตัวดำเนินการอย่างเคร่งครัดหรือไม่เนื่องจากทั้งสองเป็นประเภทอ้างอิงของ String เราจึงควรเปรียบเทียบทั้งสองอย่าง:
// toString() in this case works as well but valueOf is more semantic in this case
c.valueOf() === d.valueOf()
คิดเกี่ยวกับaและbไม่ได้ชี้ไปอ้างอิงในหน่วยความจำ แต่dอ้างอิงถึงเดียวกันcอ้างอิงสร้างขึ้นใน
ดังนั้นในตอนนี้เรากลับไปที่คำถามเกี่ยวกับสถานการณ์ที่ hooks เหล่านี้ช่วยเพิ่มประสิทธิภาพของแอป React
เพื่อช่วยในการตอบสนองเปรียบเทียบค่าอ้างอิงเช่นประเภทฟังก์ชันอาร์เรย์และวัตถุเราใช้useCallbackหรือuseMemoเพื่อห่อหุ้มการอ้างอิงเหล่านั้นให้เป็นประเภทใหม่ที่ React สามารถเปรียบเทียบและตัดสินใจว่าค่าของการอ้างอิงมีการเปลี่ยนแปลงหรือไม่
ดังนั้นหากคุณกำลังแสดงผลในระดับต่ำสุดของลำดับชั้นของคุณอาจเป็นไปได้ว่า hooks เหล่านี้จะไม่ช่วยคุณแก้ปัญหาด้านประสิทธิภาพ
อย่างไรก็ตามหากคุณใช้สิ่งนั้นในส่วนหนึ่งของแอปที่เกี่ยวข้องกับประเภทการอ้างอิงและคุณแสดงผลบ่อยครั้ง เป็นโอกาสดีที่จะใช้และช่วยให้ React ทราบว่าการอ้างอิงเหล่านั้นมีการเปลี่ยนแปลงหรือไม่เพื่อแสดงผลหรือไม่ส่วนที่เหลือหรือลำดับชั้น
ในประวัติย่อuseMemoและuseCallbackใช้เพื่อช่วยตอบสนองเพื่อดูว่าการอ้างอิงบางประเภทมีการเปลี่ยนแปลงค่าเพื่อแสดงผลคอมโพเนนต์หรือไม่