처음부터 시작하는 Java
  • React.memo
    2022년 05월 25일 10시 47분 30초에 업로드 된 글입니다.
    작성자: 원2
    728x90
    반응형

    React.memo 는 컴포넌트의 props 가 변하지 않았으면 리렌더링을 방지해서 컴포넌트의 리렌더링 성능 최적화를 해줄 수 있음

    컴포넌트에서 리렌더링이 필요한 상황에서만 리렌더링을 하도록 설정 할 수 있음

     

     

    CreateUser.js

     

    import React from "react";
    
    const CreateUser = ({username, email, onChange, onCreate}) => {
        return (
            <div>
                <input
                    name="username"
                    placeholder="계정명"
                    onChange={onChange}
                    value={username}
                />
                <input
                    name="email"
                    placeholder="이메일"
                    onChange={onChange}
                    value={email}
                />
                <button onClick={onCreate}>등록</button>
            </div>
        );
    };
    
    export default React.memo(CreateUser);

    function > const 로 변경후 감싸주면 됨

     

    export default 에 CreateUser 를 React.memo 로 감싸주기만 하면 됨

     


    UserList.js 도 해주자

     

    import React, {useEffect} from "react";
    
    const User = React.memo(function User({user, onRemove, onToggle}) {
    
        useEffect(() => {
            console.log(user);
        });
    
        return (
            <div>
                <b
                    style={{
                        cursor: 'pointer',
                        color: user.active ? 'green' : 'black'
                    }}
                    onClick={() => onToggle(user.id)}
                >
                    {user.username}
                </b>
                <span>({user.email})</span>
                <button onClick={() => onRemove(user.id)}>삭제</button>
            </div>
        );
    });
    
    // 순서상 UserList 에서 on Toggle 을 받아오고, User 에서 호출
    function UserList({users, onRemove, onToggle}) {
        return (
            <div>
                {users.map(user => (
                    <User
                        user={user}
                        Key={user.id}
                        onRemove={onRemove}
                        onToggle={onToggle}
    
                    />
                ))}
            </div>
        );
    }
    
    export default React.memo(UserList);

    마찬가지로 function > const 변경후 감싸주기

    react 개발자 도구를 보면 Memo 가 되어있다고 친절히 알려준다....

    그리고 해당 input 값에 값을 변경시켜보면 UserList 들이 리렌더링이 되지 않는것을 확인 할 수 있음

     

    그런데 User 중 하나라도 수정(클릭을 해서 false 를 ture 로 변경 한다던지..) 하면 모든 User 이 리렌더링 되고 CreateUser 도 리렌더링이 됨.

    >> 이유 users 배열이 변경 될 때 마다 해당 props 를 포함하고 있는 함수들 onCreate, onToggle, onRemove 도 영향을 받아서 새로 만들어지기 때문 > deps 에 users 가 들어있기 때문

     

    이걸 최적화 하려면 deps 에서 users 를 지우고 함수들에서 현재 useState 로 관리하는 users 를 참조하지 않게 해야함

    >> 함수형 업데이트를 사용해서 setUsers 에 등록하는 콜백함수의 파라미터에서 최신 users 를 참조 할 수 있음

    >> deps에 users 를 넣지 않아도 됌


    App.js

    onChange, onCreate, onToggle, onRemove 를 수정해보자 (onChange 는 users가 없어서 영향이 없지만 연습ㄱ)

    import React, {useCallback, useMemo, useRef, useState} from 'react';
    import CreateUser from './components/CreateUser';
    import UserList from "./components/UserList";
    
    function countActiveUsers(users) {
        console.log("active 값이 ture 인 유저의 수를 센는중...");
        return users.filter(user => user.active).length;
    }
    
    function App() {
    
        const [inputs, setInputs] = useState({
            username: '',
            email: ''
        });
    
        const {username, email} = inputs;
    
        const onChange = useCallback(
            e => {
                const {name, value} = e.target;
                setInputs(inputs => ({
                    // spread
                    ...inputs,
                    [name]: value
                }));
            }, []);
    
        // useState 를 사용하여 컴포넌트의 상태로 관리
        const [users, setUsers] = useState([
            {
                id: 1,
                username: 'velopert',
                email: 'public.velopert@gmail.com',
                active: true
            },
            {
                id: 2,
                username: 'tester',
                email: 'tester@example.com',
                active: false
            },
            {
                id: 3,
                username: 'liz',
                email: 'liz@example.com',
                active: false
            }
        ]);
    
    
        const nextId = useRef(4);
        const onCreate = useCallback(() => {
            const user = {
                id: nextId.current,
                username,
                email
            };
            // concat 함수
            setUsers(users => users.concat(user));
    
            // spread 함수
            // setUsers([
            //     //spread 문법
            //     ...users,user
            // ]);
    
            setInputs({
                username: '',
                email: ''
            });
    
            nextId.current += 1;
        }, [username, email]);
    
        const onRemove = useCallback(
            id => {
                //    user.id 가 파라미터로 일치하지 않는 우너소만 추출해서 새로운 배열을 만듬
                //    = user.id 가 id 인 것을 제거함
                setUsers(users => users.filter(user => user.id !== id));
            }, []);
    
    
        const onToggle = useCallback(
            id => {
                setUsers(users =>
                    users.map(user =>
                        user.id === id ? {...user, active: !user.active} : user
                    )
                );
            }, []);
    
        const count = useMemo(() => countActiveUsers(users), [users]);
    
        return (
            <>
                <CreateUser
                    username={username}
                    email={email}
                    onChange={onChange}
                    onCreate={onCreate}
                />
                <UserList users={users} onRemove={onRemove} onToggle={onToggle}/>
                <div>활성 사용자 수 : {count}</div>
            </>
        );
    }
    
    
    export default App;

     

    이렇게 하면 해당 항목만 리렌더링이 됌 굳ㅋ 최적화 끝

     

    리액트 개발을 할 땐 useCallback, useMemo, React.Memo 는 컴포넌트의 성능을 실제로 개선할수 있는 상황에서만 사용하자

    User 컴포넌트에 <b> 와 button 에 onClick 으로 설정해준 함수들은 useCallback 으로 재사용한다해서 리렌더링을 막을 수 있는 것이 아니라 할필요없음

     

    또한 렌더링 최적화를 하지 않을 컴포넌트에 React.memo 를 사용하는 것은 불필요한 props 비교만 하는 것이라 실제 렌더링을 방지 할 경우에만 사용하자

     

    ++

    React.memo 에서 두번째 파라미터에 propsAreEqual 함수를 사용하여 특정 값들만 비교를 하는것도 가능

    export default React.memo(
        UserList,
        (prevProps, nextProps) => prevProps.users === nextProps.users
        );

    근데 이거 잘못쓰면 버그 많이 생김

    함수형 업데이트로 전환을 안했는데 이렇게 users 만 비교하면 onToggle, onRemove 에서 최선 users 배열을 참조하지 않아서 오류 발생가능성이 있다.

    https://react.vlpt.us/basic/19-React.memo.html

    728x90
    반응형

    'JS Library > React' 카테고리의 다른 글

    Immer 라이브러리  (0) 2022.05.26
    Context API 전역 값 관리  (0) 2022.05.26
    커스텀 Hooks  (0) 2022.05.25
    useCallback 를 사용하여 함수 재사용  (0) 2022.05.25
    React Developer Tools  (0) 2022.05.24
    useMemo 를 사용하여 연산한 값 재사용하기  (0) 2022.05.24
    댓글