์๊ธ: How and when to force a React component to re-render (์ฃผ์โ ์์ญ ๋ค์ ์กด์ฌ)
๋ฆฌ์กํธ๋ ๋ณดํต ์๋์ ์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋ํ๋ค. ํ์ง๋ง ๊ฐ์ ์ ์ผ๋ก ๋ฆฌ์กํธ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋ํ๋๋ก ํ๊ธฐ ์ํด์๋ ๋ฆฌ์กํธ์ ๋ฆฌ๋ ๋ ๋ฐฉ์์ ๋ํ ์ดํด๊ฐ ํ์ํ๋ค.
์น ๋ฐ์ ์ ์์์์๋ถํฐ ์ง๊ธ๊น์ง HTML๊ณผ CSS๊ฐ ์น ์ฌ์ดํธ์ ์๊ฐ์ ์ธ ๋ถ๋ถ์ ๋ด๋นํ๊ณ ์๋ค. ํ์ง๋ง JavaScript๊ฐ ๋ฑ์ฅํจ์ผ๋ก์จ ์ฐ๋ฆฌ๋ ๋ ๋๋ง๋ ํ์ด์ง์ HTML์ ์ฝ๊ณ ์
๋ฐ์ดํธํ ์ ์๊ฒ ๋์๋ค. ์ด๋ฅผ DOM API
๋ผ๊ณ ํ๋ค.
jQuery์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ด๋ฌํ DOM API ์์ ํฅ์๋ ๊ธฐ๋ฅ๊ณผ ํธํ์ฑ์ ๊ฐ์ง ์ถ์์ ์ธ ๊ฐ๋ ์ ๋ ์ด์ด๋ฅผ ์ ๊ณตํ๊ณ , ์ด๋ฅผ ํตํด ๊ฐ๋ฐ์๋ค์ด ์ฝ๊ฒ ์น ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๊ฒ ๋์๊ธฐ ๋๋ฌธ์ ์์ฒญ๋ ์ธ๊ธฐ๋ฅผ ๋์๋ค. ํ์ง๋ง jQuery๋ ํ๊ณ๊ฐ ์์๋ค. ๊ฐ๋ฐ์๋ค์ด ๋์ ์ผ๋ก ๋ก๋๋ ์ปจํ ์ธ ๋ค์ ๋ค๋ฃฐ ๋ ์๊ธฐ๋ ๊ฒฐ์ ์ ์ธ ๋ฌธ์ ๋ค(JavaScript์ ์ํ(๋ณ์)๊ฐ ๋ฐ๋๋ ๊ฒ์ด DOM(HTML)์ ์ฆ์ ์ํฅ์ ๋ผ์น์ง ๋ชปํด์ ๊ฒฐ๊ณผ์ ์ผ๋ก ๋์ ์ฑํฌ๋ฅผ ๋ง์ถ์ง ๋ชปํ ๊ฒ)์ ํด๊ฒฐํ์ง ๋ชปํ๋ค.
๋ฐ๋ฉด์ React์ ๊ฐ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค. React๋ ์ดํ๋ฆฌ์ผ์ด์
์ ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํด JavaScript์ ์์กดํ๋ค. ํ์ด์ง์ ๊ฐ ๊ฐ์ฒด์ ๋ํ JavaScript์ ์ฐธ์กฐ๊ฐ์ ํฌํจํ๋ ์ต์์ ๋ถ๋ชจ ๊ฐ์ฒด๋ฅผ Virtual DOM
์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ์ด ๊ฐ์ DOM์ ์๊ธฐ๋ ๋ณํ๋ฅผ ์๋์ ์ผ๋ก ์ค์ DOM์ ๋ฐ์ํ๋ ๊ฒ์ด React์ ๊ฐ์ฅ ํฐ ๊ธฐ๋ฅ์ด๋ค. ๊ทธ๋ฌ๋ฉด ์ฐ๋ฆฌ๋ ์ด๋ป๊ฒ ๊ฐ์ DOM์ ์
๋ฐ์ดํธ ํ ์ ์์๊น? ์ด๋ ์ปดํฌ๋ํธ์์ state์ props๋ฅผ ๋ค๋ฃธ์ผ๋ก์จ ๊ฐ๋ฅํ๋ค.
๊ทธ๋ฌ๋ฉด ์ฌ๊ธฐ์ ํ ๊ฐ์ง ์๋ฌธ์ ์ด ์๊ธด๋ค. ๋ง์ฝ ์์ํ ๋๋ก ์ปดํฌ๋ํธ๊ฐ ์ ๋ฐ์ดํธ ๋์ง ์๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ๊ทธ๋ด ๋ ๊ฐ์ ๋ก ์ปดํฌ๋ํธ๋ฅผ ์ ๋ฐ์ดํธ ํ ์๋ ์์๊น?
์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋์ง ์๋ ์ด์
์๋์ ์ผ๋ก ์ปดํฌ๋ํธ๊ฐ ์ ๋ฐ์ดํธ ๋์ง ์๋๋ค๊ณ ํด์ ๊ฐ์ ์ ์ผ๋ก ๋ฆฌ๋ ๋๋ง์ ํ๋ ๊ฒ์ ์ข์ ๋ฐฉ๋ฒ์ด ์๋๋ค. ๊ทธ๋์ ๋ฆฌ๋ ๋๋ฅผ ๊ณ ๋ คํ๊ธฐ ์ด์ ์, ์์ฑํ ์ฝ๋๋ฅผ ๋ถ์ํ๋ ๊ฒ์ด ๋จผ์ ์ด๋ค. React ๊ธฐ๋ฅ์ ํ์ฉ์ ๊ฒฐ๊ตญ ๊ฐ๋ฐ์์ ์ฝ๋์ ๋ฌ๋ ค์๋ค.
1. state๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ ํ์ง ์์ ๊ฒฝ์ฐ
์ฌ๊ธฐ ์ด๋ฆ Juan
์ ๋ณด์ฌ์ฃผ๋ ๊ฐ๋จํ ์ฑ์ด ์๋ค.
๋ฒํผ์ ํด๋ฆญํ๋ฉด changeUserName
ํจ์๊ฐ ํธ๋ฆฌ๊ฑฐ ๋๋ฉด์ ์ด๋ฆ์ด Peter
๋ก ๋ฐ๋๋๋ก ์ค๊ณ๋๋ค. ํ์ง๋ง ๋ฒํผ์ ํด๋ฆญํด๋ ์๋ฌด๋ฐ ์ผ๋ ์ผ์ด๋์ง ์์ ๊ฒ์ด๋ค.
import { useState } from "react";
function App() {
const [user, setUser] = useState({
name: "Juan"
});
function changeUserName() {
user.name = "Peter";
setUser(user);
}
return (
<div className="App">
<p>User name: {user.name}</p>
<button onClick={changeUserName}>Change user name</button>
</div>
);
}
React๋ ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์์ ๋น๊ต ์ฆ, ์ฐธ์กฐ๊ฐ ๋น๊ต๋ฅผ ํตํด ์ด์ ๊ฐ๊ณผ ํ์ฌ ๊ฐ์ด ๊ฐ์ ๊ฐ์ฒด์ธ์ง๋ฅผ ์ฒดํฌํ๋ค. ์์ ์์์์ ๋ฆฌ๋ ๋๋ง์ด ๋ฐ์ํ์ง ์์ ์ด์ ๋ user
๊ฐ์ฒด์ name
์ด๋ผ๋ ํ๋กํผํฐ๋ง์ ์
๋ฐ์ดํธ ํ์ ๋ฟ, user
๊ฐ ๊ฐ๋ฆฌํค๋ ์ฐธ์กฐ๊ฐ์ด ์
๋ฐ์ดํธ ๋ ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ด๋ค. React๋ setUser
๊ฐ ํธ์ถ๋๊ธฐ ์ ๊ณผ ํ์ user
๋ฅผ ๊ฐ์ ์ฃผ์๋ฅผ ๊ฐ๋ ๋์ผํ ๊ฐ์ฒด๋ก ํ๋จํ๊ธฐ ๋๋ฌธ์ ์ด๋ ํ ๋ณํ๋ ๊ฐ์งํ์ง ๋ชปํ ๊ฒ์ด๋ค.
React์ ์ํ๋ ๋ถ๋ณ์ฑ์ด ์ ์ง๋์ด์ผ ํ๋ค. ์ํ์ ์๋ฃํ์ด ์ฐธ์กฐํ์ด๋ผ๋ฉด ์์ ํ ์๋ก์ด ์ฐธ์กฐ๊ฐ์ ๊ฐ๋ ์ํ๋ก ์ ๋ฐ์ดํธ๋ฅผ ํด์ค์ผํ์ง ์ด์ ์ ์ํ๋ฅผ ์ง์ ๊ฑด๋๋ ค์ ์ผ๋ถ๋ง ๋ณ๊ฒฝํด์๋ ์๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์์ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ์์ ํ๋ฉด ์ข์๊น? ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๊ฐ์ ํฌํจํ๋ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ์ ๋ฐ์ดํธ ํจ์์ ์ ๋ฌํ๋ฉด ๋๋ค.
function changeUserName() {
setUser({
...user,
name: "Peter"
});
}
๊ธฐ์กด ๊ฐ์ฒด์ ํ๋กํผํฐ ๊ฐ๋ค์ ์ ์งํ๋ฉด์ name
ํ๋กํผํฐ๋ง ์
๋ฐ์ดํธ ํ๋, spread ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด์ ๊ฒฐ๊ณผ์ ์ผ๋ก๋ ์๋ก์ด ์ฐธ์กฐ๊ฐ์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ์
๋ฐ์ดํธ ํด์ฃผ๋ ๊ฒ์ด๋ค.
2. state๊ฐ ๋ณ๊ฒฝ๋์ง ์์์๋ props๋ฅผ ์ ๋ฐ์ดํธ ํ๋ ๊ฒฝ์ฐ
์ด ์ผ์ด์ค๋ ๋ถ๊ฐ๋ฅํด๋ณด์ด์ง๋ง ์ถฉ๋ถํ ๋ฐ์ํ ์ ์๋ ์ํฉ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๋ณดํต์ ๋ฒ๊ทธ๋ฅผ ๋ฐ์์ํจ๋ค. ์๋๋ ๊ทธ ์์๋ก ์๊ณ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ฑ์ด๋ค. ์ด ์๊ณ๋ ์ฒ์ ๋ ๋๋ง ๋ ์ดํ ์๊ฐ์ด ๋ณํ์ง ์๋๋ค๋ ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
setMyTime
ํจ์๋ ๊ฐ๋ ์ฑ์ด ์ข์ง ์๊ณ , React ์ปดํฌ๋ํธ์๊ฒ ์ข์ ์ฝ๋๋ ์๋๋ค.
function App() {
let myTime;
function setMyTime() {
myTime = new Date();
setTimeout(() => {
setMyTime();
}, 1000);
}
setMyTime();
return (
<div className="App">
<Clock myTime={myTime} />
</div>
);
}
function Clock(props) {
return <p>Current time: {props.myTime.toString()}</p>;
}
App
์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง ๋๋ฉด์ setMyTime
ํจ์๊ฐ ํธ์ถ๋ ์ดํ, ๋งค ์ด๋ง๋ค setMyTime
ํจ์๊ฐ ์ฌ๊ทํธ์ถ ๋๋ฉด์ myTime
์ ์๊ฐ์ ์ฌํ ๋นํ๊ณ , ๋ฆฌ๋ ๋๋ง์ ์ํด Clock
์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ฆฌ๋ ๋๋ง์ด ๋์ง ์๋ ์ด์ ๋ App
์ปดํฌ๋ํธ๊ฐ myTime
์ ๋ณํ๋ฅผ ์์์ฐจ๋ฆฌ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ด๋ค.
React์์ ์ปดํฌ๋ํธ์ ์ํ๋ฅผ ์
๋ฐ์ดํธ ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํด์๋ ์๋์ฒ๋ผ useState
๋ฅผ ์ฌ์ฉํด ์ํ์ ์
๋ฐ์ดํธ ํจ์๋ฅผ ์ ์ํด์ผ ํ๋ค. ์ถ๊ฐ์ ์ผ๋ก useEffect
๋ฅผ ์ฌ์ฉํด ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ ๋ ๋ clearInterval
์ ํด์ ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
const [myTime, setMyTime] = useState(new Date());
useEffect(() => {
var timerID = setInterval(() => tick(), 1000);
return () => clearInterval(timerID);
});
function tick() {
setMyTime(new Date());
}
๊ฐ์ ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋ง ํ๋ ๋ฐฉ๋ฒ
๊ฐ์ ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋ ํ๋ ๊ฒ์ ๋์ฒด๋ก ์ถ์ฒ๋๋ ๋ฐฉ๋ฒ์ด ์๋๋ค. ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋์ง ์๋ ๊ฒฝ์ฐ ๋๋ถ๋ถ์ ์ฝ๋์์ ์ค๋ฅ๋ก ์ธํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ํ์ง๋ง ๋ง์ฝ์ ์ ๋ง๋ก ๊ฐ์ ๋ฆฌ๋ ๋๋ง์ด ํ์ํ ๊ฒฝ์ฐ๋ผ๋ฉด, ๋ฐฉ๋ฒ์ด ์๋ ๊ฒ์ ์๋๋ค.
1. ํด๋์คํ ์ปดํฌ๋ํธ
ํด๋์คํ ์ปดํฌ๋ํธ์์๋ ๊ณต์์ ์ผ๋ก ๋ฆฌ๋ ๋๋ฅผ ๊ฐ์ ํ๋ API๊ฐ ์ ๊ณต๋๋ค. ๋ฐ๋ก forceUpdate()
๋ฉ์๋์ด๋ค.
someMethod() {
// ์ํ์ ๋ณํ ์์ด๋ ๊ฐ์ ๋ก ๋ ๋๋ง ํ๋ค
this.forceUpdate();
}
this.forceUpdate()
๋ฅผ ํธ์ถํ๋ฉด shouldComponentUpdate()
๋ฅผ ๊ฑด๋๋ฐ๊ณ render()
๋ฉ์๋๊ฐ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ์ํ์ ๋ณํ๊ฐ ์์์๋ React๊ฐ ๊ฐ์ DOM๊ณผ DOM์ ์ํ๋ฅผ ์ฌ๋น๊ตํ๋๋ก ๊ฐ์ ํ ์ ์๋ค. ์ฌ๊ธฐ์๋ ๋ช ๊ฐ์ง ์ ์ ์ฌํญ์ด ์๋ค.
- React์์ ์์ ์ปดํฌ๋ํธ๋
shouldComponentUpdate()
๋ฅผ ํฌํจํ ์ผ๋ฐ์ ์ธ ๋ผ์ดํ์ฌ์ดํด ๋ฉ์๋๋ค์ ์ํด ์๋๋๋ฏ๋ก, ๋ฆฌ๋ ๋๋ง์ ๊ฐ์ ํ ์ ์๋ ๊ฑด ์ค์ง ํ์ฌ ์ปดํฌ๋ํธ ๋ฟ์ด๋ค. - ๊ฐ์ ๋ฆฌ๋ ๋๋ง์ ํด๋ ์ฌ์ ํ ๊ฐ์ DOM์ DOM์ ์ํ์ ๋น๊ตํ์ฌ ๋ฆฌ๋ ๋์ ์ ํจ์ฑ์ ํ๋จํ๊ธฐ ๋๋ฌธ์, ๋งํฌ์ ์ ๋ณํ๊ฐ ์์ ๋๋ง DOM์ด ์ ๋ฐ์ดํธ ๋ ๊ฒ์ด๋ค.
2. ํจ์ํ ์ปดํฌ๋ํธ
ํจ์ํ ์ปดํฌ๋ํธ์์๋ ๋ฆฌ๋ ๋๋ฅผ ๊ฐ์ ํ๋ ๊ณต์ API๊ฐ ์กด์ฌํ์ง ์๋๋ค. ๋๋ฌธ์ ๋ช๊ฐ์ง ํธ๋ฆญ์ ์ฌ์ฉํด์ผ ํ๋ค.
- ์ํ ๊ฐ์ฒด๋ฅผ ์๋ก์ด ์ฐธ์กฐ๊ฐ์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ก ๋ฐ๊พธ๊ธฐ
someMethod() {
// ์ํ๊ฐ ๋ณํ ๊ฒ์ฒ๋ผ ํ๋ด๋ด ๊ฐ์ ๋ก ๋ ๋๋ง ํ๋ค
setUser({ ...user });
}
user
๊ฐ ๊ฐ์ฒด์ด๊ณ React๋ ์์ ๋น๊ต๋ฅผ ํ๊ธฐ ๋๋ฌธ์ spread ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด์ ์๋ก์ด ์ฐธ์กฐ๊ฐ์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ก ์
๋ฐ์ดํธ ํ๋ค๋ฉด, React๋ ์ํ๊ฐ ๋ณ๊ฒฝ๋์๋ค๊ณ ํ๋จํด ๋ฆฌ๋ ๋๋ฅผ ํ๋ ๊ฒ์ด๋ค. ์ด๋ ์ํ๊ฐ ๊ฐ์ฒด๋ ๋ฐฐ์ด์ธ ๊ฒฝ์ฐ์ ์ ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
- ๋น ์ํ ๋ณ์๋ก ์ ๋ฐ์ดํธ ๋ฐ์์ํค๊ธฐ
useState
๋ก ์
๋ฐ์ดํธ ํจ์๋ง ์ ์ธํ๊ณ , ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง์ด ํ์ํ ๋ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํด ์
๋ฐ์ดํธ ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
import { useState, useCallback } from "react";
function App() {
const [, updateState] = useState(); // ์ํ ๋ณ์๋ ์ ์ธํ์ง ์๋๋ค
const forceUpdate = useCallback(() => updateState({}), []);
console.log("rendering...");
return (
<div className="App">
<h1>Time to force some updates</h1>
<button onClick={forceUpdate}>Force re-render</button>
</div>
);
}
๊ทธ๋ผ ์ด์ Force re-render
๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋ ๋์ด ์ฝ์์ ๋ก๊ทธ๊ฐ ์ฐํ ๊ฒ์ด๋ค. ์ด ๋ useCallback
์ ์ฌ์ฉํด ์ฒซ ๋ ๋ ์์ forceUpdate
ํจ์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด๋๊ณ , ์์ ์ปดํฌ๋ํธ์ props๋ก ์์ ํ๊ฒ ์ ๋ฌํ๋๋ก ํ๋ค.
๊ฒฐ๋ก
๋ฐ๋ณตํด ์๊ธฐํ์ง๋ง ๊ฐ์ ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋ ํ๋ ๊ฑด ์ข์ ๋ฐฉ๋ฒ์ด ์๋๋ค. ๊ทธ๋ฐ ์ผ์ด ์ผ์ด๋์ง ์๋๋ก ์ข์ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ฐ์ ๋์ด์ผ ํ๋ค.
'๐ป๐ > ๊ฐ๋ฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[React] ์ฑ๋ฅ ์ต์ ํ:: React.memo๋ฅผ ์ฌ์ฉํ ์ปดํฌ๋ํธ Memoization (0) | 2021.09.15 |
---|---|
[Redux-Saga] Error: call: argument of type {context, fn} has undefined or null fn (0) | 2021.09.12 |
[JS] Web APIs์ ๋ํด (0) | 2021.08.28 |
[JS] ๋ฐฐ์ด APIs: splice์ slice์ ๋น๊ต (0) | 2021.08.19 |
[React] Webpack์ผ๋ก ๊ตฌ์ถํ React ํ๋ก์ ํธ์์ ํ๊ฒฝ ๋ณ์(.env) ์ฌ์ฉํ๊ธฐ (1) | 2021.08.19 |