React.memo를 사용하여 성능을 최적화하는 방법

Nov 21 2020

React 프론트 엔드를 사용하여 체스 게임을 만들었습니다. 원래는 모든 동작이 즉시 구현되었지만 헤더의 배경을 변경하여 누가 차례인지 (흰색 이동 여부에 따라 흰색 또는 검은 색 배경) 및 기타 유사한 기능을 추가하는 등의 추가 기능을 추가 한 후 내 앱이 눈에 띄게 속도가 느려졌습니다. 나는 그것이 이러한 유형의 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")
    }

props를 인쇄하는 console.log가 이동 당 8 번 (원래 두 번) 명령문을 인쇄하기 때문에 책임이 있습니다.

클래스가 아닌 기능적 구성 요소를 사용하고 있으며 최적화에 대한 연구로 다음과 같은 솔루션을 얻었습니다.

React Hooks-shouldComponentUpdate를 어떻게 구현합니까?

소품을 기대하지 않는 경우 모든 구성 요소를 React.memo ()로 래핑해야합니까?

shouldComponentUpdate를 React Hooks와 함께 사용하는 방법?

모두 간단한 경우를 가리키고 React.memo있지만 구현하려고 할 때 얻을 수있는 것은 과다한 'props'가 정의 된 오류가 아니기 때문입니다 (많은 props를 사용할 때마다 하나씩).

Details.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를 사용할 수 없습니까?

소품에 대한 액세스를 유지하면서 성능을 어떻게 최적화합니까?

답변

4 JanCássio Nov 21 2020 at 02:31

첫째, 일반적으로 프런트 엔드에서 성능을 테스트 할 때 염두에 두어야 할 사항입니다.

당신은 결코 당신이있는 거 검사 성능의 DevTools로로 활동, 성능 많이 귀하의 응용 프로그램을 감소하면서 DevTools로 열어 두지.

둘째, 모두 useMemouseCallback당신이, 철저하게 렌더링은 사용자 정의 구성 요소 내에서 다른 사용자 정의 구성 요소를 렌더링하지 않을 경우 가능한이 가장 중요하기 전에 렌더링되는 소품을 렌더링하지 않을 경우 어떤 성능 향상을 제공하지 않습니다, 아마, 당신은하지 않습니다 그 후크도 사용해야합니다.

그렇다면 성능을 향상시키기 위해 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 참조가 d 참조와 엄격하게 동일합니다 . 둘 다 String의 참조 유형이기 때문에 c의 값이 연산자를 d사용 하는 값과 완전히 같은지 비교할 수 없습니다. ===둘 다 다음과 같이 비교해야합니다.

// toString() in this case works as well but valueOf is more semantic in this case
c.valueOf() === d.valueOf()

생각해 ab메모리 참조 만 가리 키지 않는 d받는 참조 같은 에서 만든 참조 c.

이제이를 염두에두고 이러한 후크가 React 앱의 성능을 향상시키는 상황에 대한 질문으로 돌아가 보겠습니다.

도움말을 비교 반응 참조 예를 들어 기능, 배열 및 객체 유형과 같은 값은, 우리가 사용 useCallback하거나 useMemo하는 캡슐화 비교하고 경우에 결정할 수 반작용 새로운 유형으로 이러한 참조 기준의 값이 변경되었다.

따라서 계층 구조의 가장 낮은 수준 만 렌더링하는 경우 이러한 후크는 성능 문제를 해결하는 데 도움이되지 않을 것입니다.

그러나 참조 유형을 다루는 앱의 일부에서 사용하고 자주 렌더링하는 경우. 이를 사용할 수있는 좋은 기회이며 React가 참조가 변경되었는지 여부를 알 수 있도록 도와줍니다.

이력서에서, useMemo그리고 useCallback일부 여부를 확인하는 데 도움이 반응에 사용되는 참조 형식이 구성 요소를 렌더링하는 값을 변경했습니다.