January 02, 2021
이번 회사에 입사하기 전까진 React이외에 Angular나 Vue를 따로 공부해본적이 없었다. 그땐 리액트를 조금 더 하드하게 쓰고 싶었고 잘쓰는 방향을 연구하는게 더 즐거웠었다.
그런데 이번에 입사한 힐링페이퍼에서는 Frontend 주 기술 스택으로 Vue로 통합 하고 있다. 기존의 Legacy React코드도 Vue로 옮겨지고 있다.
Vue를 쓰는걸 알고 입사했고, 여러 방향으로 요즘 트렌드 라이브러리의 장점과 단점들을 학습하고 싶었다.
Vue에서는 장점이 굳이 최적화작업을 하지 않아도 굉장히 빠른 웹 어플리케이션을 짧은 코드로 작성 할 수 있다. 이를 작게나마 확인해보기 위해서 다음과 같은 가설을 두고 테스트를 진행하였다.
또 반대로 React가 Vue와 동일한 Life Cycle을 가진 최적화 컴포넌트를 가지려면 어떻게 customizing을 해야하는가?
간단한 컴포넌트를 만들기 위해서 아래와 같은 구조로 작성하였다.
child1Value
, Child2: child2Value
)결론: Parent의 state 값이 변경되면 child 컴포넌트 1,2 모두 자신에게 종속된 property와 관계없이 항상 렌더링 된다.
// Parent.jsx
import { useState } from 'react';
import Child1 from './Child1';
import Child2 from './Child2';
import './styles.css'
const Parents = () => {
const [common, setCommon] = useState('공통 값 입니다.');
const [child1Value, setChild1Value] = useState(0)
const [child2Value, setChild2Value] = useState(0)
return (
<div className="wrapper">
<div className="child1">
<h1>Child1 Component</h1>
<Child1
common={common}
handleCommon={setCommon}
child1Value={child1Value}
handleChild1Value={setChild1Value}
/>
</div>
<div className="child2">
<h1>Child2 Component</h1>
<Child2
common={common}
handleCommon={setCommon}
child2Value={child2Value}
handleChild2Value={setChild2Value}
/>
</div>
</div>
)
}
export default Parents;
child1Value
라는 값이 변경되었을 때 Child1 component만 렌더링 되어야 하는데 Child2 component까지 렌더링 되는 이슈가 있으므로 이 부분을 해결할 필요가 있다.결론: Parent의 state 값이 변경되었을 때 child 컴포넌트에서는 자신이 가진 property가 있을 경우에만 렌더링 한다.
<template>
<div class="wrapper">
<div>
<h1>Child1 Component</h1>
<child1
:common="common"
:child1Value="child1Value"
@handle-common="setCommon"
@handle-child1-value="setChild1Value"
/>
</div>
<div>
<h1>Child2 Component</h1>
<child2
:common="common"
:child2Value="child2Value"
@handle-common="setCommon"
@handle-child2-value="setChild2Value"
/>
</div>
</div>
</template>
<script>
import Child1 from './Child1'
import Child2 from './Child2'
export default {
data() {
return {
common: '공통 값 입니다.',
child1Value: 0,
child2Value: 0,
}
},
components: {
Child1,
Child2,
},
methods: {
setCommon: function (newText) {
this.common = newText;
},
setChild1Value: function (value) {
this.child1Value = value;
},
setChild2Value: function (value) {
this.child2Value = value;
},
}
}
</script>
child1Value
값을 변경 시켰을 때 child1 component만 리렌더링이 발생하고 child2 component는 리 렌더링이 발생 되지 않는다. (그 반대도 마찬가지)위 코드로 봤을 때 코드의 양은 React나 Vue나 그들만의 문법이 있을뿐 실제로 코드의 양은 그렇게 차이는 없다. 다만 React에서는 렌더링 최적화가 해결되지 않은 상태로 렌더링이 발생하고 있고 Vue에서는 렌더링 최적화가 알아서 잘 되어 있는 것으로 보인다.
shouldComponentUpdate
와 같은 비교 라이프사이클을 이용하던가(현재는 deprecated 됨), 아니면 PureComponent
or React.memo()
를 이용하여야 한다.굉장히 간단하다. React.memo()
를 사용하여 child 컴포넌트가 받고 있는 props의 shallow compare를 통해 변한 값이 있을 때에만 리 렌더링을 하도록 하면된다.
import { useEffect, useCallback, memo } from "react";
const Child1 = (props) => {
// ... 생략 ...
return (
<div>
<h1>현재상태: {child1Value}</h1>
<h2>{common}</h2>
<button onClick={onCommonClick}>공통 값 변경</button>
<button onClick={onChild1ValueClick}>{ child1Value }</button>
</div>
)
}
// 아래처럼 React의 memo로 해당 child 컴포넌트를 감싼다.
export default memo(Child1);
React에서 React.memo
를 사용하여 Child 컴포넌트의 자신의 props의 변화가 없다면 (기존 props와 새로 인입된 props) 리 렌더링 하지 않는 방식으로 vue와 동일하게 리 렌더링 최적화를 할 수 있다.
리액트에서의 memoization
기법은 실제로 유용하지만(useCallback, useMemo 등…), 언제나 쉽게 변하는 컴포넌트, 변수 혹은 함수에 memo를 모두 선언해서 사용한다는건 어쩌면 더 안 좋은 패턴이 될 수도 있다. (오히려 더 많은 메모리를 사용하고 코드가 복잡해질수도 있다고 생각한다.)
memoization 기법을 쓰기 위해 어느정도의 빈번한 렌더링을 기준으로 잡고 써야 하는지는 조금 더 연구가 필요할 것 같다.
근데 Vue는 이런 부분에선 참 편한것 같다.!!