목표
- 리액트의 리렌더링에 대해서 알아본다.
- 이벤트 핸들러를 다루어 본다.
<body>
<div id="root"></div>
<script>
const rootElement = document.getElementById("root");
const getRandomNumber = () => {
const number = Math.floor(Math.random() * (10 - 1) + 1);
const element = `
<button>${number}</button>
<p>1</p>
`;
rootElement.innerHTML = element;
};
setInterval(getRandomNumber, 1000);
</script>
</body>
<body>
<div id="root"></div>
<script type="text/babel">
const rootElement = document.getElementById("root");
const getRandomNumber = () => {
const number = Math.floor(Math.random() * (10 - 1) + 1);
const element = (
<>
<button>{number}</button>
<p>1</p>
</>
);
ReactDOM.render(element, rootElement);
};
setInterval(getRandomNumber, 1000);
</script>
</body>
리플로우(reflow)와 리페인트(repaint)
- 리플로우는 HTML 문서를 구성하는 요소의 위치나 크기가 변경되었을 때 각 요소를 재배치 하는 작업을 말한다.
- 리페인트는 HTML 문서의 전체 또는 일부 영역의 스타일이 변경되었을 때 브라우저가 변경된 스타일을 다시 적용하는 작업을 말한다. 화면의 구조가 바뀌지 않은 이상 리페인트만 실행된다.
엘리먼트의 타입이 다르다면? 이전 엘리먼트는 버리고 새로 그린다.
엘리먼트의 타입이 같다면? key를 먼저 비교하고 그 후 props를 비교해서 변경사항을 반영한다. 즉, 리액트는 엘리먼트의 두 속성을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 갱신한다.
이러한 비교 알고리즘을 통해 새로운 엘리먼트 트리를 반환하는 것을 재조정(reconciliation)이라고 하는데, 이는 React 공식 문서에서 확인할 수 있다.
<div className="before" title="stuff" />
<div className="after" title="stuff" />
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />
<div id="root">
<button id="alert">button</button>
</div>
<script>
const button = document.getElementById("alert");
button.addEventListener("click", () => {
alert("click");
});
button.addEventListener("mouseout", () => {
alert("mouseout");
});
</script>
<div id="root"></div>
<script type="text/babel">
const rootElement = document.getElementById("root");
const onClick = () => {
alert("click");
};
const onMouseOut = () => {
alert("mouseOut");
};
const element = (
<button onClick={onClick} onMouseOut={onMouseOut}>
button
</button>
);
ReactDOM.render(element, rootElement);
</script>
카멜 케이스(camelCase)
- 각 단어의 첫문자를 대문자로 표기하고 붙여쓰되, 맨처음 문자는 소문자로 표기하는 방법으 로 띄어쓰기 대신 대문자로 단어를 구분한다.
- 예) backgroundColor, className 등
<body>
<div id="root"></div>
<script type="text/babel">
const rootElement = document.getElementById("root");
const state = { keyword: "", typing: false, result: "" };
const App = () => {
const onChange = (e) => {
setState({ keyword: e.target.value, typing: true });
};
const onClick = () => {
setState({
typing: false,
result: `find result of ${state.keyword}`
});
};
return (
<>
<input onChange={onChange} />
<button onClick={onClick}>search</button>
<p>
{state.typing ? `searching... ${state.keyword}` : state.result}
</p>
</>
);
};
const setState = (newState) => {
Object.assign(state, newState);
render();
};
const render = () => {
ReactDOM.render(<App />, rootElement);
};
render();
</script>
</body>
onChange 함수는 input 엘리먼트에 값을 입력하면 setState 함수를 호출한다.
onClick 함수는 state 객체의 typing 속성을 확인하여 조건에 맞는 값을 찍어낸다.
Object.assign()
- 출처 객체로부터 모든 열거할 수 있는(enumerable) 하나 이상의 속성(own properties)들을 목표 객체로 복사한다. 이는 수정된 목표 객체를 반환한다.
- 아래 코드에서 returnedTarget 객체의 c 속성을 7로 수정했을 때 target 객체의 c 속성이 똑같이 변한 것으로 보아 두 객체는 서로 참조되고 있는 것을 확인할 수 있다.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
Object.assign(returnedTarget, {c: 7});
console.log(target);
// expected output: Object { a: 1, b: 4, c: 7 }