스터디/React

[Next.js] 컴포넌트간 데이터 넘기기, 리랜더링방지

_leezoee_ 2022. 6. 21. 14:12

1. 하위 컴포넌트에서 상위 컴포넌트로 props 넘기기

2. 넘겨진 props 에 의해 상위 컴포넌트 전체 리랜더링 되는거 막기

 

먼저 설명할 컴포넌트의 구조를 그림으로 그려보면,

[컴포넌트 구조 도식화]

이런식으로 상위 A 컴포넌트 안에 B, C, D 를 두었다 (select box 나 input, date picker 같은 컴포넌트)

이때 B에서 state를 변화했을때 A 에서 이를 어떻게 알까?

 

Angular 같은 경우는 하나의 service 에 변수를 빼서 그 변수를 구독하는 식으로 여러 컴포넌트에서 썼었는데 리액트는 어떻게 사용하는 지 모르겠어서 구글링을 해보았다.

 

상위 컴포넌트에서 state를 정의해두고 useState 함수에 해당하는 값을 하위 컴포넌트로 넘겨주면 된다고 한다.

 

//상위컴포넌트, 도식화 A
const [select, setSelect] = React.useState();
console.log("select is "+select);

...

return(//propFunction은 아무 이름이나 하면 됨
	<ComponentB propFunction={setSelect} />
);
//하위컴포넌트, 도식화 B

...

return(//rsuit에 Cascader 라이브러리 컴포넌트를 사용했음. onchage 에 props로 넘어온 함수 넣어줌
    <div>
    	<Cascader onchange={props.propFunction} />
    <div>
);

이런식으로 상위 컴포넌트 A 안에서 B 컴포넌트 호출 시 setState 에 해당하는 함수명을 넘겨주고, 하위 컴포넌트 B 안에서 해당 함수를 onclick 이나 onchange 등 때에 따라 호출 하도록 하면 해당 state가 B에서 변경 되고 A로 타고 올라간다.(타고 올라간다고 표현하는게 맞나싶지만 설명하기 쉽게 그렇게 표현)

 

여기까지했을 때 A 에서 콘솔 로그에 잘 찍히는걸 볼수있는데 문제가 하나 발생함.

 

A 단에 모든 컴포넌트가 리랜더링 되는 문제가 발생..

 

B에서 state가 바껴 A의 setState 해당하는 함수가 호출되므로 A단 컴포넌트가 전부 리랜더링 되는게 맞다. 이론적으로는

 

그치만 C와 D 컴포넌트가 table 이나 chart 같이 많은 데이터들을 불러와야 하는 컴포넌트 인 경우 이런식으로 불필요하게 리랜더링 시키면 안되기에. 다시 구글링 시작.

 

useMemo 를 사용하면 원하는 state 가 변경됐을 경우만 리랜더링 할 수 있도록 막을 수 있다고 한다.

A 단에서 C와 D를 호출 하는 소스를 useMemo 안에 넣어서 수정했다.

 

//도식화 A 

//변경 전 소스 
const [select, setSelect] = React.useState();
console.log("select is "+select);

return (
	<div>
        <ComponentB propFunction={setMeterType} />
        <ComponentC data={data1} />
        <ComponentD data={data2} />
    </div>
);
//도식화 A 

//변경 후 소스 
const [select, setSelect] = React.useState();
console.log("select is "+select);

const memoComponentC = useMemo(() => {
    return <ComponentC data={data1} />
},[data1]); //data1이 바꼈을때만 리랜더링

const memoComponentD = useMemo(() => {
    return <ComponentD data={data2} />
},[data2]); //data2가 바꼈을때만 리랜더링

return (
	<div>
        <ComponentB propFunction={setMeterType} />
        {memoComponentC}
        {memoComponentD}
    </div>
);

 

C와 D를 useMemo로 리턴받아 랜더링 해주니까 B가 바뀌어도 C와 D는 새로고침 되지않게 되었다!

 

인터넷 찾아보니까 useMemo는 거의 useCallback 과 함께 쓰던데 이건 좀 더 스터디 해봐야할듯하다