2022.07.27(Wed)
[TIL] Day64
[SEB FE] Day65
: Document Object Model
(๋ฌธ์ ๊ฐ์ฒด ๋ชจ๋ธ). ๋ธ๋ผ์ฐ์ ๊ฐ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ง๋ ๋ชจ๋ธ
โจย ๋ฌธ์ ๊ฐ์ฒด๋?
: JS์ ๊ฐ์ ์คํฌ๋ฆฝํ
์ธ์ด๊ฐ ํ๊ทธ๋ค์ ์ ๊ทผํ๊ณ ์กฐ์ํ ์ ์๋๋ก ๋ธ๋ผ์ฐ์ ๊ฐ ํ๊ทธ๋ค์ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๊ฐ์ฒดํ ์ํจ ๊ฒ์ ์๋ฏธ!
๐ตย ํธ๋ฆฌ๋ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๋ ํจ๊ณผ์ ์ผ๋ก ํ์ํ๊ธฐ ์ํด ์ฌ์ฉ โ ๋น ๋ฅธ ์๋ฃ ํ์ ์ฑ๋ฅ์ด ์ฅ์ ์ธ ์๋ฃ๊ตฌ์กฐ
๐ย ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ DOM์ JS์ ๊ฐ์ ์คํฌ๋ฆฝํ ์ธ์ด๊ฐ ์ ๊ทผํ๊ณ ํ์ํ๋ ์๋๊ฐ ๋น ๋ฅด๋ฏ๋ก ๋ณ๊ฒฝ / ์ ๋ฐ์ดํธ ์๋ ๋ํ ๋น ๋ฆ
โจย DOM์ด ๋ณ๊ฒฝ & ์ ๋ฐ์ดํธ๋๋ค = ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง ์์ง์ด Reflowํ๋ค!
๐ย JS๋ก ์กฐ์ํ๋ DOM์ ์์๊ฐ ๋ง์์๋ก ๋ชจ๋ DOM ์ ๋ฐ์ดํธ์ ๋ํด ๋ฆฌํ๋ก์ฐ๋ฅผ ํด์ผ ํ๋ฏ๋ก DOM ์ ๋ฐ์ดํธ์ ๋ํ ๋น์ฉ์ด ๋ง์ด ๋ค๊ฒ ๋จ
๐ซฅ like Real DOM
์ ๊ฐ๋ฒผ์ด ์ฌ๋ณธ ๋๋ ?
์ถ์ํ๋ JS ๊ฐ์ฒด ํํ๋ฅผ ๊ฐ์ง๊ณ ์์
์ค์ DOM๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก HTML
๋ฌธ์ ๊ฐ์ฒด ๊ธฐ๋ฐ!
์ค์ DOM ๊ฐ์ฒด์ ์ ๊ทผํ์ฌ ์กฐ์ํ๋ ๊ฒ์ด ์๋๋ผ Virtual DOM
์ ์ ๊ทผํ์ฌ ๋ฐ๋ ๋ถ๋ถ๋ง ์ ์ฉ!
โย ์ค์ DOM ๊ฐ์ฒด์ฒ๋ผ ํ๋ฉด ๋ด์ฉ์ ์ง์ ๋ณ๊ฒฝ โย โ ํจ์ฌ ์๋ Fast!
Virtual DOM Tree
์ ์ด์ & ํ์ฌ ๋ฒ์ ๊ฐ์ ์ฐจ์ด ๊ณ์ฐ โ ๋ถ๋ถ์ ์ผ๋ก ๋ฆฌ๋ ๋๋งโจย ๊ฐ์
key
ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ ์ฌ๋ฌ๋ฒ ๋ ๋๋ง์ ๊ฑฐ์ณ๋ ๋ณ๊ฒฝ๋๋ฉด ์ ๋๋ ์์ ์์๊ฐ ๋ฌด์์ธ์ง ์์๋ผ ์ ์์React
๋ ๊ธฐ์กด๊ณผ ์๋กญ๊ฒ ๋ณ๊ฒฝ๋ Virtual DOM Tree
๋ฅผ ๋น๊ตํ ๋, ํธ๋ฆฌ์ Level
์์๋๋ก ์ํํ๋ ๋ฐฉ์์ผ๋ก ํ์Level
(์์น)๋ผ๋ฆฌ ๋น๊ต! (BFS
; ๋๋น์ฐ์ ํ์)โจย ๋ค๋ฅธ ํ์ ์ DOM Element์ธ ๊ฒฝ์ฐ
DOM Tree
๋ ๋ถ๋ชจ์ ์์ ๊ฐ์ ํ๊ทธ๊ฐ ํ์ ์ ์ด๋ผ ๋ถ๋ชจ ํ๊ทธ๊ฐ ๋ฌ๋ผ์ง๋ค๋ฉดReact
๋ ์ด์ ํธ๋ฆฌ๋ฅผ ๋ฒ๋ฆฌ๊ณ , ์๋ก์ด ํธ๋ฆฌ๋ฅผ ๊ตฌ์ถ! โ ์ด์ DOM ๋
ธ๋๋ค์ ์ ๋ถ ํ๊ดดUnmount
) โ ๊ธฐ์กด state
ํ๊ดดโจย ๊ฐ์ ํ์ ์ DOM Element์ธ ๊ฒฝ์ฐ
React
๋ ์ต๋ํ ๋ ๋๋ง ํ์ง ์๋ ๋ฐฉํฅ์ผ๋ก ์ต์ํ์ ๋ณ๊ฒฝ ์ฌํญ๋ง ์
๋ฐ์ดํธ๐ฟย React
๋ ์ โ ์๋๋ก ์์ฐจ์ ์ผ๋ก ๋น๊ตํ๋ฏ๋ก, List ์ฒ์ ๋ถ๋ถ์ ์๋ฆฌ๋จผํธ ์ฝ์
์ ์ด์ ์ ์ฝ๋์ ๋นํด ํจ์ฌ ๋์ ์ฑ๋ฅ์ ๋
<ul>
<li>first</li>
<li>second</li>
</ul>
// ์์ ์๋ฆฌ๋จผํธ์ ๋์ ์๋ก์ด ์์ ์๋ฆฌ๋จผํธ๋ฅผ ์ถ๊ฐ -> Good
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
// ์์ ์๋ฆฌ๋จผํธ๋ฅผ ์ฒ์์ ์ถ๊ฐ -> Bad
// ์์ ๋
ธ๋๊ฐ ์๋ก ๋ค๋ฅด๋ค๊ณ ์ธ์ง -> ๋ฆฌ์คํธ ์ ์ฒด๊ฐ ๋ฐ๋์๋ค๊ณ ์๊ฐํจ
// => ์๋กญ๊ฒ ๋ ๋๋งํด๋ฒ๋ฆผ -> ๋นํจ์จ์ ์ธ ๋์ ๋ฐฉ์!
<ul>
<li>third</li>
<li>first</li>
<li>second</li>
</ul>
๐ย ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด key
์์ฑ ์ง์ โ ํจ์จ์ ์ผ๋ก ๊ฐ์ DOM ์กฐ์ ๊ฐ๋ฅ
key
๋ฅผ ๊ฐ๊ณ ์๋ค๋ฉด, React
๋ ๊ทธ key
๋ฅผ ์ด์ฉํด ๊ธฐ์กด & ์๋ก์ด ํธ๋ฆฌ์ ์์์ด ์ผ์นํ๋์ง ํ์ธ ๊ฐ๋ฅkey
์์ฑ์๋ ์ ์ผํ ๊ฐ(ex. Id
) ๋ถ์ฌ ํด์ฃผ๊ธฐ!๐ซงย ๋ณต์ก๋๊ฐ ์ปค์ง์๋กโฌ๏ธ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆผ
๐ซง ๋๋น์ฐ์ ํ์(BFS
): ๊ฐ๊น์ด ์ง์ ๋ถํฐ ํ์ํ๋ฉฐ, ๋ฉ๋ฆฌ ์๋ ์ง์ ์ ๋์ค์ ํ์
ย ๐ย ์ปดํฌ๋ํธ ์ฌ์ด์์ ์ํ ๋ก์ง ์ฌ์ฌ์ฉ ์ด๋ ต
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
this.handleIncrease = this.handleIncrease.bind(this);
}
handleIncrease = () => {
this.setState({
counter: this.state.counter + 1
})
}
render(){
return (
<div>
<p>You clicked {this.state.counter} times</p>
<button onClick={this.handleIncrease}>
Click me
</button>
</div>
)
}
}
ย ๐ย ํด๋์คํ ์ปดํฌ๋ํธ์ ๋นํด ํจ์ฌ ๋ ์ง๊ด์ ์ด๊ณ , ๋ณด๊ธฐ ์ฌ์
// useState() Hook์ ํธ์ถํด ํจ์ ์ปดํฌ๋ํธ(function component) ์์ state๋ฅผ ์ถ๊ฐํ ํํ
// ์ด state๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง ๋์ด๋ ๊ทธ๋๋ก ์ ์ง๋จ
function Counter () {
const [counter, setCounter] = useState(0); // ์ปดํฌ๋ํธ ๋ฆฌ๋ ๋๋ง๋์ด๋ state๋ ๊ทธ๋๋ก ์ ์ง
const handleIncrease = () => {
setCounter(counter + 1)
}
return (
<div>
<p>You clicked {counter} times</p>
<button onClick={handleIncrease}>
Click me
</button>
</div>
)
}
: ํจ์ํ ์ปดํฌ๋ํธ์์ ์ํ๊ฐ ๋ฑ์ ์ฌ๋ฌ ๊ธฐ๋ฅ ์ฌ์ฉ์ ํธ๋ฆฌํ๊ฒ ํด์ฃผ๋ ๋ฉ์๋ (ํด๋์คํ ์ปดํฌ๋ํธ์์ ๋์ โ)
โจย Hook ์ฌ์ฉ ๊ท์น
โจย ์ปดํฌ๋ํธ๋ ๋ณดํต ์ํ๊ฐ ๋ณ๊ฒฝ๋๊ฑฐ๋ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง์ด ๋ ๋๋ง๋ค ๋ฆฌ๋ ๋๋งํ๋ ๊ตฌ์กฐ๋ก ์ด๋ฃจ์ด์ ธ ์์
โจย ๋ ๋๋ง ์ต์ ํ๋ฅผ ์ํ Hook: useCallback
, useMemo
: ํน์ ๊ฐ(value)๋ฅผ ์ฌ์ฌ์ฉํ๊ณ ์ ํ ๋ ์ฌ์ฉํ๋ Hook
import { useMemo } from "react";
function Calculator({value}){
// const result = calculate(value);
const result = useMemo(() => calculate(value), [value]);
return (
<>
<div>
{result}
</div>
</>
)
}
// add.js
export const add = (num1, num2) => {
console.log("์ซ์๊ฐ ๋ค์ด์ต๋๋ค.");
return Number(num1) + Number(num2);
};
// -------------------------------------------
// App.js
const [name, setName] = useState("");
const [val1, setVal1] = useState(0);
const [val2, setVal2] = useState(0);
// name์ด ๋ณ๊ฒฝ๋ ๋๋ add() ํธ์ถ
const answer = add(val1, val2);
// useMemo()๋ฅผ ์ด์ฉํ์ฌ val1, val2 ๊ฐ์ด ๋ฐ๋๋๋ง add()๊ฐ ํธ์ถ๋๋๋ก ๋ณ๊ฒฝ!
const answer = useMemo(() => add(val1, val2), [val1, val2]);
value
๊ฐ์ด ๊ฐ์ ๊ฒฝ์ฐ์ ์ด์ value
๊ฐ์ ๊ทธ๋๋ก ์ฌํ์ฉMemoization
๊ฐ๋
๊ณผ ๊ด๊ณ!: ๊ธฐ์กด์ ์ํํ ์ฐ์ฐ์ ๊ฒฐ๊ณผ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด๋๊ณ , ๋์ผํ ์
๋ ฅ์ด ๋ค์ด์ค๋ฉด ์ฌํ์ฉํ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ
๐ย ์ค๋ณต ์ฐ์ฐ์ ํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฑ ์ฑ๋ฅ ์ต์ ํ!
: Memoization
๊ธฐ๋ฒ์ ์ด์ฉํ Hook์ผ๋ก, ํจ์์ ์ฌ์ฌ์ฉ์ ์ํด ์ฌ์ฉํ๋ Hook
import React, { useCallback } from "react";
function Calculator({x, y}){
// const add = () => x + y;
const add = useCallback(() => x + y, [x, y]);
return (
<>
<div>
{add()}
</div>
</>
)
}
// List.js
function List({ getItems }) {
const [items, setItems] = useState([]);
useEffect(() => {
console.log("์์ดํ
์ ๊ฐ์ ธ์ต๋๋ค.");
setItems(getItems());
}, [getItems]);
return (
<div>
{items.map((item) => (
<div key={item}>{item}</div>
))}
</div>
);
}
// -------------------------------------------
// App.js
const [input, setInput] = useState(1);
const [light, setLight] = useState(true);
// input์ ์ซ์ ๋ณ๊ฒฝ ์ธ์๋ ๋คํฌ๋ชจ๋ ๋ฒํผ ํด๋ฆญ์์๋ ๋์
const getItems = () => {
return [input + 10, input + 100];
};
// useCallback()๋ฅผ ์ด์ฉํ์ฌ input ๊ฐ์ด ๋ฐ๋๋๋ง setItems() ํธ์ถ๋๋๋ก ๋ณ๊ฒฝ!
const getItems = useCallback(() => [input + 10, input + 100], [input]);
๐ย ์์ ์ปดํฌ๋ํธ์ props๋ก ํจ์๋ฅผ ์ ๋ฌํด์ค ๋ useCallback
์ ์ฌ์ฉํ๊ธฐ ์ข์
โจย useCallback
์ ์ฐธ์กฐ ๋๋ฑ์ฑ์ ์์กด
false
์ถ๋ ฅReact
๋ ๋ฆฌ๋ ๋๋ง ์ ํจ์๋ฅผ ์๋ก ๋ง๋ค์ด์ ํธ์ถuseCallback
์ ์ด์ฉํด ํจ์ ์์ฒด๋ฅผ ์ ์ฅํ ํ, ๋ค์ ์ฌ์ฉ