react 리렌더링 줄이기 (react Memo)

이명진·2023년 5월 5일
0

cat bot에서 새로운 기능인 고양이가 있는지 없는지 ? 에 대해 선택을 받도록 기능 구현을 하였다.

사이트 : https://chatbot-1gi.pages.dev/

input 리렌더링

input + radio 를 이용하여 만들었는데 useState로 input값을 관리하다 보니
input 값을 선택할때마다 리렌더링이 되어 버렸다.

배경 값이 Math.random값으로 변화가 되는데 input을 클릭하다 보니 뒤의 배경이 자꾸 변경되는 것이 문제였다.

또한 성능상으로 문제가 발생할것 같아서 검색좀 하다 보니 React.Memo에 대해서 알게 되었다.

기존에도 함수에 리렌더링을 줄이기 위해 useCallback, Memo에 대해서 공부를 했었는데 직접 적용하게 되었다.

특히나 함수에 적용하는 것이 아니라 input에 적용하기 위해서 컴포넌트 로 빼서 Memo를 제작하게 되었다.

타입 스크립트가 있어서 오류가 자꾸발생해서 코드를 작성하는데 쉽지는 않았지만 해결할수 있었다.

내 코드

const RadioCat: React.FC<{ getValue: (value: string) => void }> = React.memo(
    ({ getValue }) => {
        const [hasCat, setHasCat] = useState({ trigger: true, value: "yes" });
        const catValue = (e: React.ChangeEvent<HTMLInputElement>) => {
            const { value } = e.target;
            setHasCat({ value: value, trigger: value == "yes" });
            getValue(value);
        };
        return (
            <CatRadio>
                <h2>잠깐 냥, 너는 반려묘가 있냥? 😼</h2>

                <input
                    type="radio"
                    name="hasCat"
                    value="yes"
                    checked={hasCat.trigger}
                    onChange={catValue}
                    id="select"
                />
                <label htmlFor="select">물론, 고양이를 키우고있지!!</label>

                <input
                    type="radio"
                    name="hasCat"
                    value="no"
                    checked={!hasCat.trigger}
                    onChange={catValue}
                    id="select2"
                />
                <label htmlFor="select2">
                    아니, 고양이는 없지만 궁금한게 있어.
                </label>
            </CatRadio>
        );
    }
);

렌더링 고민

기존에는 그냥 부모 컴포넌트에서 useRef로 관리해서 렌더링을 하지 않도록 해볼까 하고 생각하며 로직을 짰었다.
값은 제대로 전달되는데 radio input을 누를때마다 그려지지 않아서 그런지 선택되지 않는 오류가 있었다.
어쩔수 없이 useState로 그려줘야 할것 같은데.. 그래서 useMemo를 사용하게 되었다.

사용

useMemo를 이용해서 RadioCat을 만들어 주고 부모 컴포넌트에 바로 적용해줬다.
따로 컴포넌트를 파일로 뺀게 아니여서 import없이 바로 넣었다.

부모 코드

const LandingPage = () => {
 <생략>
    return (
        <Container catBg={randomBackgroundImg}>
        <생략>
            <RadioCat getValue={getValue} />
         <생략>       
	 </Container>
    );
};

문제

그런데 문제가 있었다. 고양이의 유무를 받아서 다음 채팅창에서 그에 맞는 인삿말을 꺼내기 위해 값을 알아야 했었는데
부모한테 값을 어떻게 줄까 고민하게 되었다. 자식이기 때문에 부모에게 값을 전달해야 하는데..
마침 메인 챗(다음 컴포넌트)가 자식 컴포넌트가 아니었기 때문에 useNavigate 로 state값을 전달해주었다.

그리고 memo컴포넌트에는 함수를 전달해줘서 값을 받아왔다.
getValue 함수를 만들어서 값을 받아오고 전달해줄수 있었다


 let catValue = useRef("yes");
    const getValue = (value: string): void => {
        catValue.current = value;
    };

state로 받아서 값을 관리할까 했었는데 재렌더링을 줄이기 위해 memo를 쓴것이라서 useRef로 값을 받아왔다.
그리고 메인 챗으로 이동할때는 navigate로 값을 전달해줬다.

 const navigate = useNavigate();
   const goMain = () => {
       navigate("/catbot", { state: { hasCat: catValue.current } });
   };

값을 받을때는 useLocation을 활용하면 된다.


 const location = useLocation();
location.state.값이름 

으로 값을 받아올수 있다 .

아래는 구현 사항이다. 체크 한 사항이 다르면 인삿말을 다르게 해준다.

memo를 사용하니 확실히 렌더링이 없다.

고양이 있다

고양이 없다

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글