-
useState, ํด๋ก์ ๋ฅผ ํ์ฉํ์ฌ ๋์ํ๋ค๊ณ ?TECH 2024. 1. 27. 21:48
์ด๋ฒ ํฌ์คํ ์์๋ ํด๋ก์ ์ ๋ํด์ ๊ฐ๋จํ ์์๋ณด๊ณ ,
ํด๋ก์ ๊ฐ ํ์ฉ๋๋ ์์ ์ค ํ๋์ธ
useState
์ ๋ด๋ถ ๋์ ๋ฐฉ์์ ์์ธํ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.โ๏ธ ํด๋ก์ ๋?
ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ฌ์ฉ๋๋ ์ค์ํ ํน์ฑ ์ค ํ๋๋ก, ํจ์์ ๊ทธ ํจ์๊ฐ ์ ์ธ๋ ๋ ์์ปฌ ํ๊ฒฝ๊ณผ์ ์กฐํฉ์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ ์์ปฌ ์ค์ฝํ๋ฅผ ๋ฐ๋ฅด๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ ํ์์ ๋๋ค.
W3C School์์๋ ํด๋ก์ ๋ฅผ ํจ์๊ฐ privateํ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ค๊ณ ์ค๋ช ํฉ๋๋ค.
์ด ์ค๋ช ์ด ํด๋ก์ ์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ดํดํ๋ ๋ฐ ๋์์ด ๋์์ต๋๋ค.
์ฌ๊ธฐ์ ๋ ์์ปฌ ์ค์ฝํ๋?
์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ ํจ์๊ฐ ํธ์ถ๋๋ ์์น๊ฐ ์๋ ํจ์๋ฅผ ์ด๋์ ์ ์ํ๋์ง์ ๋ฐ๋ผ ํจ์์ ์์ ์ค์ฝํ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์์ ์ค์ฝํ์ ๋ํ ์ฐธ์กฐ๋ ํจ์ ์ ์๊ฐ ํ๊ฐ๋๋ ์์ ์ ํจ์๊ฐ ์ ์๋ ํ๊ฒฝ์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค.
์ ๋ฆฌ๋ฅผ ํด ๋ณด์๋ฉด,
¹ ์ธ๋ถ ํจ์๋ณด๋ค ์์ ์ค์ฝํ์ ์๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ์ค์ฒฉ ํจ์๊ฐ ๋ ์ค๋ ์ ์ง๋๋ ๊ฒฝ์ฐ
² ์ค์ฒฉ ํจ์๊ฐ ์ด๋ฏธ ์๋ช ์ฃผ๊ธฐ๊ฐ ์ข ๋ฃ๋ ์ธ๋ถ ํจ์์ ๋ณ์๋ฅผ ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ
์ด ์ค์ฒฉ ํจ์๋ฅผ ํด๋ก์ ๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
ํด๋ก์ ์ธ ์ค์ฒฉ ํจ์
const x = 10; function outerFunc() { const x = 1; function innerFunc() { console.log(x); // 1 } innerFunc(); } outerFunc();
ํด๋ก์ ๊ฐ ์๋ ์ค์ฒฉ ํจ์
const x = 10; function outerFunc() { const x = 1; function innerFunc() { const y = 2 console.log(y); // 2 } innerFunc(); } outerFunc();
โ๏ธ ํด๋ก์ ์ ํ์ฉ
ํด๋ก์ ๋ ์ํ๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ์งํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
๋ค์ ๋งํด, ์ํ๋ฅผ ์๋ํ์ฌ ์๋์น ์์ ๋ณ๊ฒฝ์ ๋ฐฉ์งํ๊ณ ํน์ ํจ์๋ก๋ง ์ํ ๋ณ๊ฒฝ์ ํ์ฉํ๊ธฐ ์ํด ์ฌ์ฉํ ์ ์์ต๋๋ค.
let a = 1; function add() { a += 1; return a; } console.log(add()); // 2 console.log(add()); // 3 console.log(add()); // 4 a = 999; console.log(add()); // 1000
์ ์์ ์ ๊ฐ์ด
a
๋ฅผ ์ ์ญ ๋ณ์๋ก ์ฌ์ฉํ ๊ฒฝ์ฐ, ์๋์น ์์ ์ํ ๋ณ๊ฒฝ์ด ์ด๋ฃจ์ด์ง ์ ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.const add = (function() { let a = 1; return function() { a += 1; return a; } })(); console.log(add()); // 2 console.log(add()); // 3 console.log(add()); // 4 console.log(a); // Uncaught ReferenceError: a is not defined
์ ์์ ์ ๊ฐ์ด ํด๋ก์ ๋ฅผ ํ์ฉํ์ฌ ์ํ๊ฐ ์๋์น ์๊ฒ ๋ณ๊ฒฝ๋์ง ์๋๋ก ์๋ํ์ฌ ์ํ๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ์งํ ์ ์์ต๋๋ค.
โ๏ธ
useState
๊ฐ ํด๋ก์ ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์useState
์ ๋ด๋ถ ๋์์ ๊ด๋ จํ ๋ค์ ๋ฌธ๋จ์ 2019๋ JSConf์์ ๋ฐํ๋ React Hooks์ useState์ ๋ํ ๋ฐํ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค.function useState(initVal) { let _val = initVal; const state = () => _val; const setState = (newVal) => { _val = newVal; }; return [state, setState]; } const [count, setCount] = useState(1); console.log(count()); setCount(2); console.log(count());
์์ฃผ ๊ฐ๋จํ๊ฒ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก
useState
๋ฉ์๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.๊ทธ๋ฌ๋ ์ํ ๊ฐ์ ์กฐํํ๊ธฐ ์ํด getter ํจ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ด ์๋ ๊ธฐ์กด์
useState
๊ฐ ๊ฐ์ ๊ฐ์ ธ์ค๋ ํจํด์ฒ๋ผ ๋ณ๊ฒฝํ๊ณ ์ถ์ต๋๋ค.๋จ๊ณ์ ์ผ๋ก ๋ฆฌํฉํ ๋ง์ ๊ฑฐ์ณ ๋ด ์๋ค.
const React = (function() { function useState(initVal) { let _val = initVal; const state = () => _val; const setState = (newVal) => { _val = newVal; }; return [state, setState]; }; return { useState }; })(); const [count, setCount] = React.useState(1); console.log(count()); // 1 setCount(2); console.log(count()); // 2
์ฆ์ ์คํ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ React ๋ชจ๋ ๋ด์์
useState
๋ฅผ ์ ์ํ๋๋ก ๋ณ๊ฒฝํ์ต๋๋ค.const React = (function () { /* 3๏ธโฃ */ let _val; function useState(initVal) { const state = _val || initVal; const setState = (newVal) => { _val = newVal; }; return [state, setState] } /* 2๏ธโฃ */ function render(Component) { const C = Component(); C.render(); return C; } return { useState, render }; })(); /* 1๏ธโฃ */ function Component() { const [count, setCount] = React.useState(1); return { render: () => console.log(count), click: () => setCount(count + 1), } } let App; App = React.render(Component); // 1 App.click(); App = React.render(Component); // 2
1๏ธโฃ ๋ฆฌ์กํธ๋ฅผ ํ๋ด๋ด๊ธฐ ์ํ
Component
๋ฅผ ๋ง๋ค์ด ์ค๋๋ค.Component
๋ด๋ถ์์๋render
๋ฉ์๋๋กcount
๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๊ณ , ๋ฒํผ ์ญํ ์ ํclick
๋ฉ์๋๋ฅผ ๋์ดcount
์ ๊ฐ์ ์ฆ๊ฐ์ํต๋๋ค.
2๏ธโฃ React ๋ชจ๋์๊ฒ๋ ๋ ๋๋งํ ์ปดํฌ๋ํธ๊ฐ ์๋ค๋ ์ฌ์ค์ ์๋ ค ์ฃผ์ด์ผ ํฉ๋๋ค.React ๋ชจ๋ ๋ด์
render
ํจ์๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ ํ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ ์ปดํฌ๋ํธ๋ฅผ ๋ฐํํฉ๋๋ค.3๏ธโฃ ๊ทธ๋ฆฌ๊ณ React ๋ชจ๋์
useState
๋ด์์ ์ฌ์ฉ๋๊ณ ์๋_val
๋ณ์๋ฅผ ์์๋ก ๋์ด์ฌ๋ ค React ํจ์์ ์ค์ฝํ๋ก ์ด๋์ํต๋๋ค. (ํด๋ก์ ์ ์ฉ๋ฒ ํ์ฉ)_val
๊ฐ์useState
ํจ์์ ์ํด ์ฐธ์กฐ๋๊ณ ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค.์ด
useState
์๋ ๋ฒ๊ทธ๊ฐ ์์ต๋๋ค. ์ํ๋ฅผ ํ๋ ๋ ์ถ๊ฐํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ํ์์ด ๋ฐ์ํฉ๋๋ค.function Component() { const [count, setCount] = React.useState(1); const [text, setText] = React.useState("apple"); return { render: () => console.log({count, text}), click: () => setCount(count + 1), text: word => setText(word) }; }; var App = React.render(Component); // {count: 1, text: 'apple'} App.click(); var App = React.render(Component); // {count: 2, text: 2} App.text("banana"); var App = React.render(Component); // {count: 'banana', text: 'banana'}
์ด ๋ฐฉ์์
useState
_val
์ด๋ผ๋ ๋จ ํ ๊ฐ์ ๋ณ์๋ฅผ ์ฌ์ฉํ๊ณ ์๊ณ ,count
์text
๋ ๋ค_val
๋ณ์์ ๋ฎ์ด ์์์ง๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ ํ์์ด ๋ฐ์ํฉ๋๋ค.์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฆฌ์กํธ์์๋ ๋ด๋ถ์ ์ผ๋ก ์ธ๋ฑ์ค(
idx
)๋ฅผ ๋๊ณ , ์ํ ๋ฐฐ์ด(hooks
)์ ์ฌ์ฉํฉ๋๋ค.const React = (function () { let hooks = []; let idx = 0 function useState(initVal) { const state = hooks[idx] || initVal; const _idx = idx; // freeze idx using closure const setState = (newVal) => { hooks[_idx] = newVal; }; idx++ return [state, setState]; }; function render(Component) { idx = 0; const C = Component(); C.render(); return C; }; return { useState, render }; })(); function Component() { const [count, setCount] = React.useState(1); const [text, setText] = React.useState("apple"); return { render: () => console.log({count, text}), click: () => setCount(count + 1), text: word => setText(word) }; }; var App = React.render(Component); // {count: 1, text: 'apple'} App.click(); var App = React.render(Component); // {count: 2, text: 'apple'} App.text("banana"); var App = React.render(Component); // {count: 2, text: 'banana'}
๋ํ ์ฌ๊ธฐ์ ๋ฆฌ์กํธ ํ ์ด ๋ฐ๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ, ์ค์ฒฉ ํจ์ ๋ด์์ ํธ์ถํ ์ ์๋ค๋ ๊ท์น์ ์ด์ ์ ๋ํด์๋ ์์ธํ ์ ์ ์์ต๋๋ค.
function Component() { if (Math.random() > 0.5) { const [count, setCount] = React.useState(1); } const [text, setText] = React.useState("apple"); // โฌ ๏ธ return { render: () => console.log({count, text}), click: () => setCount(count + 1), text: word => setText(word) }; }
๋ค์๊ณผ ๊ฐ์ด
useStae
๋ฅผ ์กฐ๊ฑด๋ฌธ ๋ด์์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ํ์ดํ๊ฐ ๊ฐ๋ฆฌํค๋useStae
์ ์ธ๋ฑ์ค๋ 0์ด ๋ ์๋ ์๊ณ 1์ด ๋ ์๋ ์์ต๋๋ค.์ด์ ๊ฐ์ ๋์์ ์ํ๊ฐ
hooks
๋ฐฐ์ด ๋ด์์ ์์ธกํ ์ ์๋ ์์น์ ์ ์ฅ๋ฉ๋๋ค.๋ฐ๋ผ์ ํ ์ ์ํ๊ฐ ์ผ๊ด๋ ์์๋ก ์ ์ฅ๋์ด ์์ธก ๊ฐ๋ฅํ๊ณ ์์ ์ ์ผ๋ก ๋์ํ๋ ๊ฒ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์๋ง ์ฌ์ฉ๋์ด์ผ ํฉ๋๋ค.
โ๏ธ ์ฐธ๊ณ
๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive โ 24์ฅ ํด๋ก์
Can Swyx recreate React Hooks and useState in under 30 min? - JSConf.Asia
'TECH' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ฆฌ์กํธ์์ requestAnimationFrame ์ฌ์ฉ ์ ์ฃผ์ํ ์ (0) 2024.03.17 React Hook Form์ ์๋ก ๋น์ทํ ๊ธฐ๋ฅ๋ค์ ๋น๊ตํด ๋ณด์ (0) 2024.02.03 React์์ Event Handler๋ ์ด๋ป๊ฒ ๋์ํ ๊น์? (0) 2024.01.11 Zero Runtime CSS-in-JS์ ๋ํด ์์๋ณด์ (1) 2024.01.06 React์์ TMap API ์ฌ์ฉํ๊ธฐ (1) 2023.12.30