-
virtual DOM, props, state카테고리 없음 2023. 4. 16. 15:04
돔이란?
DOM (Docment Obfect Model)
문서 객체 모델(DOM, Document Object Model)은 XML이나 HTML 문서에 접근하기 위한 일종의 인터페이스이다.
이 객체 모델은 문서 내의 모든 요소를 정의하고, 각각의 요소에 접근하는 방법을 제공한다.
add버튼을 눌렀을때 additem()함수가 실행되면서 5개씩 보이게되고 누를때마다 계속 위에 리얼돔이 실행이 된다.
append가 실행될때마다 리얼돔이 실행이 되서 잦은 업데이트로 브라우저는 필요이상으로 연산을 실행해야하고 성능적으로 저하된다.
또한, 최근 모던 웹은 SPA(Single Page Application)을 사용한다. 하나의 웹 페이지를 어플리케이션처럼 구성하는 SPA에서는 HTML 문서 자체가 하나이며, 여러 동적인 기능이 들어가기 때문에 안그래도 리소스가 모두 합쳐진 무거운 HTML 문서를 지속적으로 재랜더링 해줘야한다는 문제점이 발생하게 되었다.
이처럼 기존에는 화면의 변경사항을 DOM을 직접 조작하여 브라우저에 반영했다. 하지만, 이방법의 가장 큰 단점은 DOM트리가 수정될 때마다 렌더 트리가 계속해서 실시간으로 갱신된다는 점이다.
가상돔을 사용하지 않았을때의 단점
- 느린 UI 업데이트: 가상 DOM을 사용하지 않으면 매번 실제 DOM을 직접 조작해야 합니다. 실제 DOM 조작은 비용이 많이 들기 때문에 UI 업데이트가 느려질 수 있습니다. 특히 복잡한 UI 구조에서는 더 큰 성능 저하가 발생할 수 있습니다.
- 불필요한 리렌더링: 가상 DOM을 사용하지 않으면 상태(state)나 속성(props)이 변경되지 않았더라도 전체 UI를 리렌더링해야 합니다. 이로 인해 성능 저하가 발생하고 불필요한 리렌더링이 발생할 수 있습니다.
- 복잡한 UI 관리: SPA에서는 복잡한 UI 상태를 관리해야 할 수 있습니다. 가상 DOM을 사용하지 않으면 상태 변화를 직접 추적해야 하므로 코드가 복잡해질 수 있고 유지보수가 어려워질 수 있습니다.
- 사용자 경험 저하: 느린 UI 업데이트와 불필요한 리렌더링으로 인해 사용자 경험이 저하될 수 있습니다. 페이지 반응성이 떨어지거나 일시적인 화면 깜빡임이 발생할 수 있습니다.
- 불안정성: SPA에서는 사용자의 상호작용에 따라 동적으로 UI가 변경되는 경우가 많습니다. 가상 DOM을 사용하지 않으면 DOM 조작이 일어나는 타이밍에 의존성이 발생하여 UI의 안정성이 떨어질 수 있습니다.
Virtual DOM
virtual DOM은 말그대로 가상돔이다.
React와 같은 일부 JavaScript 라이브러리 및 프레임워크에서 사용하는 개념이다.
가상돔을 사용하게되면 업데이트 될 수 있는 요소들을 모아서 가상돔에 실행시키고 그다음 한번에 업데이트를 시키는 리얼돔에 업데이트를 시키는 방법으로 과부화 되는걸 막을 수 있다.
Virtual DOM DOM React오 같은 라이브러리에서 사용하는 가상 객체 모델 브라우저가 직접 렌더링하는 HTML문서를 나타내는 객체 모델
이를 직접 조작한다.변경된 부분만 찾아서 업데이트하기 때문에 성능 저하를 최소화 조작할 때 브라우저가 실제로 화면을 다시 그리는 작업이 필요하다. 추상화된 개념으로, 개발자가 코드를 작성하기 쉽고 유지보수하기 용이 조작할 때는 개발자가 직접 코드를 작성해야하므로 코드가 복잡해지고 유지보수가 어려워질 수 있다. 변경된 부분만 적용되어, 이전 상태와 새로운 상태를 비교하고 차이점을 찾는 과정이 필요하다. 상태 변화가 발생하면 즉시 실제 DOM에 적용된다. 렌더링이 다시 발생한다. 이렇게 보면 virtual DOM이 무조건 좋다 라고 생각이 들 수 있따.
그러나 virtual DOM은 메모리에 추가 오버헤드가 발생하므로, DOM보다는 더 많은 자원을 소비한다.
또한, virtual DOM을 사용하는 경우에도 최종적으로는 실제 DOM조작이 필요하다. 따라서 매우 빠른 화면 업데이트가 필요한 경우,
virtual DOM보다는 직접 DOM을 조작하는 것이 더 효율적일 수 있다.
Props(properties)
props란?
상위 컴포넌트가 하위 컴포넌트에 값을 전달할 때 사용하는 속성(React 컴포넌트의 입력 매개변수 역할)
이유는 props는 변경이 불가능한 데이터로, 상위 컴포넌트에서 하위 컴포넌트로 일방적으로 전달된다. 즉 하위 컴포넌트에서 상위 컴포넌트로 데이터를 전달할 수 는 없다.
React컴포넌트에서는 props를 사용하여 상태(state)를 변경하는 함수를 전달할 수도 있다. 이를 통해 하뒤 컴포넌트에서 상태를 변경할 수 있으며, 이를 다시 상위 컴포넌트로 전달하여 데이터를 업데이트 할 수 있다.
Props는 간단하게 전달되는 데이터이므로 , 단순한 값을 전달하는 것뿐만 아니라 객체, 함수, 배열 등 다양한 형태의 데이터를 전달할 수 있다.
상위컴포넌트에서 하위컴포넌트로 변경할 id값을 불러오는 함수를 작성하고 props로 보내준다.
function App() { const handleDone = (id) => { const updatedDone = data.map(item => { if (item.id === id) { return { ...item, done: true }; } return item; }); setData(updatedDone); } return( <TodoWorking todoList={data} onDelete={handleDelete} onDone={handleDone} /> } }
아래 이미지에서 전달받은 props로 버튼을 클릭한 대상의 id를 콜백함수를 통해 상위 컴포넌트로 전달해주면 상위컴포넌트에선 전달받은 id를 매개변수로 사용해서 상위컴포넌트 내에서 사용할 수 있다.
const TodoDone = (props) => { return ( <button onClick={() => props.onDone(e.id)}>취소하기</button> ) }
props의 주의할 점
1. props는 읽기 전용이다.
React에서 props는 컴포넌트 외부에서 전달되는 읽기 전용 데이터다. 즉 컴포넌트 내에서 props 값을 직접 변경하거나 수정하면 안된다.
대신 props를 통해 전달받은 데이터를 사용하여 컴포넌트 내부의 동작을 변경하거나 렌더링 결과를 다르게 구성할 수 있다.
2. props의 이름은 CamelCase로 작성되어야 한다.
이는 HTML에서 사용되는 속성 이름과 구별하기 위함이다. 예를들어 class속성은 className으로 작성해야 한다.
3. props의 타입을 검사하고 유효성을 검증해야 한다.
props의 타입이나 값이 유효하지 않은 경우 예기치 않은 동작이 발생할 수 있다. 이를 방지하기 위해서 prop-types라이브러리르 사용하여 props의 타입을 검사하고 유효성을 검증하는 것이 좋다.
이를 통해 개발자의 실수나 런타임 오류를 방지할 수 있다.
4. props의 개수를 최소화해야 한다.
props는 컴포넌트 간에 데이터를 전달하는 방식이기 때문에 props의 개수가 많아질수록 컴포넌트간의 의존성이 높아지고 유지보수가 어려워진다. 따라서 가능한 props의 개수를 최소화하고 필요한 경우에는 컴포넌트를 분리하는것이 좋다.
5. props의 값을 변경해야 할 경우 상위 컴포넌트에서 콜백 함수를 전달하는 방식을 사용해야 한다.
props의 값을 변경해야 할 경우 직접 props값을 변경하는 것이 아니라, 상위 컴포넌트에서 콜백 함수를 전달하여 상위 컴포넌트에서 props값을 변경하는 방식을 사용해야 한다. 이를 통해 props의 값을 변경할 때 생기는 부작용을 최소화 할 수 있다.
state
state란?
컴포넌트가 갖는 테마처럼 값이 바뀔 동적인 데이터이고, 상태를 바꾸는 등의 관리는 컴포넌트가 직접 관리하게 된다.
state는 컴포넌트가 렌더링 될때마다 해당 컴포넌트의 상태가 변경될 수 있다.
state를 변경하면 React는 자동으로 컴포넌트를 다시 렌더링하며, 변경된 state를 반영한 새로운 결과를 화면에 표시한다.
state를 사용하면 사용자의 상호작용에 따라 컴포넌트의 상태를 동적으로 변경할 수 있습니다. 예를 들어, 사용자가 버튼을 클릭하거나 입력 양식을 작성하는 경우, 해당 컴포넌트의 state를 변경하여 컴포넌트의 렌더링 결과를 동적으로 변경할 수 있습니다.
예를들어
function App() { let count = 0 console.log(count) const handlePlus = ()=>{ count++ } const handleMinus = ()=>{ count-- } return ( <> {count} <button onClick={handlePlus}>+</button> <button onClick={handleMinus}>-</button> </> ); }
+버튼을 누르면 1씩 증가되도록 - 버튼을 눌면 1씩 감소되도록 코드를 짜고 브라우저에서 실행시켰을때
console에는 1씩 증가되거나 감소되는게 확인되지만 브라우저화면에는 숫자가 0으로 고정되어 바뀌지 않는걸 볼 수 있다.
이유는 리엑트에서 브라우저 화면에 다시 렌더링이 되게하려면 무조건 setState값이 변경이 되어야지만 state값이 변경이 되어 화면에 보여질 수 있기 때문이다.
function App() { const [count, setCount] = useState(0) console.log(count) const handlePlus=()=>{ setCount(count+1) } const handleMinus=()=>{ setCount(count-1) } return ( <> {count} <button onClick={handlePlus}>+</button> <button onClick={handleMinus}>-</button> </> ); }
이렇게 useState를 사용해서 버튼이 눌릴때마다 setCount가 변경이 되도록 하면 브라우저 화면에서도 ++가 되는걸 볼 수 있다.
이처럼 리엑트의 정말 기본적이고 중요한 virtual DOM, props, state를 알아봤는데 알고있던 내용과 몰랐던 내용, 강의에 안나왔던 내용도 스스로 찾아서 알게되니 정말 유용한 시간이였다.