⛏ state 선언 위치에 따른 rendering 차이

너무도 당연한 얘기를 실험과 함께 정리해보고자 한다.
솔직히 React를 쓰면서, 'state가 바뀌면, re-rendering이 됩니다!' 정도만 알고 코딩했던 것 같다. 하지만 그런 와중에도

'rendering이 적게 일어나게 하려면 state를 어떤 식으로 나눠야 할까?',
'state를 어떻게 두면 rendering이 많이 일어날까?'

와 같이, state에 따른 rendering에 대한 호기심과 명확히 알아보고자 하는 욕구가 있었다.

여러 경우를 비교하는게 딱히 어려운 일도 아닌데, 자꾸 미뤄온 스스로를 반성하며 당연하지만 눈으로 확인하면 확실하게 기억할 수 있는 시도를 기록해본다.

준비

state는 count라는 숫자와 name이라는 문자열을 준비했다.
실험 case는 다음과 같다.

  1. App.js 에 두 state 모두 선언.
  2. 각 state를 component로 분리하고, App.js 에 import해서 사용.
  3. state는 App.js에서 선언하고, stateless component에서 각 state를 받아서 사용.
  4. redux와 같은 전역 상태 관리툴에서 선언.

실험

1️⃣App.js에 두 state 모두 선언.

코드

// App.js
const App = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("");
  const inputRef = useRef();
  
  return (
    <>
      {/* Name 부분 코드 */}
      <span>{name}</span>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setName(inputRef.current.value);
          inputRef.current.value = "";
        }}
      >
        <input ref={inputRef} />
      </form>
      
      {/* Count 부분 코드 */}
      <span>{count}</span>
      <br />
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </>
  )
}

결과

=> 전체(App.js)가 re-rendering 됨.
Name과 Count를 Component로 따로 분류하지 않았기 때문에, App Component 전체가 re-rendering 된다.

2️⃣ 각 state를 component로 분리하고, App.js 에 import해서 사용.

코드

// App.js
const App = () => {
  return (
    <Name />
    <Count />
  )
}

// Name.js
const Name = () => {
  const [name, setName] = useState("");
  
  return (
    <>
      {/* Name 부분 코드 */}
    </>
  )
}

// Count.js
const Count = () => {
  const [count, setCount] = useState(0);
  
  return (
    <>
      {/* Count 부분 코드 */}
    </>
  )
}

결과

=> 각 component만 re-rendering됨.

3️⃣ state는 App.js에서 선언하고, stateless component에서 각 state를 받아서 사용.

코드

// App.js
const App = () => {
  const [name, setName] = useState("Kim");
  const [count, setCount] = useState(0);
  
  return (
    <>
      <Name name={name} setName={setName} />
      <Count count={count} setCount={setCount} />
    </>
  )
}

// Name.js
const Name = ({ name, setName }) => {
  return (
    <>
      {/* Name 부분 코드 */}
    </>
  )
}

// Count.js
const Count = ({ count, setCount }) => {
  return (
    <>
      {/* Count 부분 코드 */}
    </>
  )
}

결과

=> Name이나 Count 둘 중 하나만 바꾸더라도 App, Name, Count 모두 re-rendering 됨.
App이 rendering 되는 건 state 때문이지만, Name과 Count는 state를 props로 전달받았기 때문에, props가 변하면서 rendering 되는 것.

4️⃣ redux와 같은 전역 상태 관리툴 사용

4️⃣-1. redux + 3️⃣번 조건(App.js에 state)

결과

=> 3번 결과와 동일하게 모든 component가 re-rendering됨.

4️⃣-2. redux + 2️⃣번 조건(각 component에 state)

결과

=> 2번 결과와 동일하게 부분적으로 re-rendering됨.
(2번 조건과 결과 동일.)

4️⃣-3. redux + 2️⃣번 조건 + App.js에서 name state 구독 (구독만 하고 사용 X)

구독한 name을 사용하지는 않고, 구독만 한 상태에서 name state를 변경해봤다.
(return 구문 안에서 name 사용 X)

코드

// App.js
...
const name = useSelector(state => state.name);
...

결과

=> name이 바뀌면 App component도 re-rendering.

4️⃣-4. redux + 2️⃣번 조건 + App.js에서 setName 사용 (name state 구독 X)

App.js에서 name을 구독하지 않고, setName이라는 action만 사용했다.
코드는 Name.js에 있는 <input> 부분과 동일하다.

코드

// App.js
...
return (
  ...
    <span>input box in App.js</span>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setName(inputRef.current.value);
          inputRef.current.value = "";
        }}
      >
        <input ref={inputRef} />
     </form>
  ...
)

결과

=> name component만 re-rendering됨.

결론

예상한대로 state가 변하면, re-rendering이 발생했다. redux사용 시, 구독한 state가 변하면 역시나 re-rendering되는 것도 확인했다. 조금 신기했던 건, 구독해놓고 render하지 않아도 state의 변화에 반응한다는 점이다. 그리고 state를 구독하지 않고 action만 사용하면 re-rendering 되지 않는 점도 신기했다. 어쩌면 당연한 결과인지도 모르지만, 평소 state와 action을 떼어놓고 사용하지 않다보니 낯선 결과로 느껴졌다.

redux의 경우, reselect를 이용하면 re-rendering을 방지할 수 있다. 자세한 건 다시 공부해고 정리해볼 생각이다.

좋은 웹페이지 즐겨찾기