๋ ธ๋ง๋์ฝ๋์ ReactJS๋ก ์ํ ์น ์๋น์ค ๋ง๋ค๊ธฐ ๊ฐ์ข์ ์ฒ์ ~ 3.4์ ๋ด์ฉ์ ๋ชจํฐ๋ธ๋ก ์์ฑํ์์ต๋๋ค.
JavaScript๋ก ํ ์ดํ๋ก์ ํธ๋ฅผ ํ๋๋ง ํด๋ด๋ document.querySelector
๋ก ์์๋ฅผ ๊ณ ๋ฅด๊ณ innerText
ํ๋กํผํฐ๋ก HTML์ ์์ ํ๋, ์์ฃผ ๋ถํธํ ์ผ์ด ๋น์ผ๋น์ฌํ๊ฒ ์ผ์ด๋๋ค๋ ์ฌ์ค์ ์ฒด๊ฐํ๋ค.
์ด๋ฒ ๊ธ์์ getElementById, createElement, JSX, React Hooks๋ฅผ ์ฐจ๊ทผ์ฐจ๊ทผ ๋์ ํด๋ณด๋ฉด์ Vanila JS์์ React๋ก ์ฝ๋๊ฐ ๋ณํ๋ ๊ณผ์ ์ ์ดํด๋ณด์.
v1.0 Vanila JS
<!DOCTYPE html>
<html>
<body>
<h3>Total clicks: 0</h3>
<button id="btn">Click me</button>
<script>
<!-- ํ๋จ ์ฐธ๊ณ -->
</script>
</body>
</html>
let counter = 0;
const h3 = document.querySelector('h3');
const button = document.getElementById('btn');
function handleClick() {
counter += 1;
h3.innerText = `Total clicks: ${counter}`;
}
button.addEventListener('click', handleClick);
์ด๋ฏธ ์ง์ํ์ จ๋ค์ํผ, ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค 1์ฉ ์ฌ๋ผ๊ฐ๋ ์ฝ๋๋ค.
v2.0 createElement
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script>
<!-- ํ๋จ์ ์ฐธ๊ณ -->
</script>
</body>
</html>
react์ react-dom ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํ๋ค.
let counter = 0;
const root = document.getElementById('root');
const h3 = React.createElement('h3', null, 'Total clicks: 0');
function handleClick() {
counter += 1;
const h3 = React.createElement('h3', null, `Total clicks: ${counter}`);
const container = React.createElement('div', null, h3, btn);
ReactDOM.render(container, root);
}
const btn = React.createElement(
'button',
{
id: 'btn',
onClick: handleClick,
},
'Click me'
);
const container = React.createElement('div', null, h3, btn);
ReactDOM.render(container, root);
์ด์ ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ์?
HTML์๋ div#root
๋ฐ์ ์๋ค. CSR์ ๊ธฐ๋ฏธ๊ฐ ์ฌ์ฌ ๋ณด์ธ๋ค.
React.createElement()
๋ก ์์๋ฅผ ๋ง๋ ๋ค.ReactDOM.render()
๋ก ๋ ๋๋งํ๋ค.
- ์ฐธ๊ณ :
createElement(type, props, ...children)
ํ๋กํ ํ์ ๋งํฌ
v3.0 JSX
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
<!-- ํ๋จ ์ฐธ๊ณ -->
</script>
</body>
</html>
babel ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํ๋ค.
let counter = 0;
const root = document.getElementById('root');
function handleClick() {
counter += 1;
const H3 = () => <h3>Total Clicks: {counter}</h3>;
const Container = () => (
<div>
<H3 /> <Button />
</div>
);
ReactDOM.render(<Container />, root);
}
const H3 = () => <h3>Total Clicks: 0</h3>;
const Button = () => (
<button id="btn" onClick={handleClick}>
Click me
</button>
);
const Container = () => (
<div>
<H3 /> <Button />
</div>
);
ReactDOM.render(<Container />, root);
์ด์ ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ์?
JS ๋์ JSX๋ฅผ ์ฌ์ฉํ์๋ค.
JSX๋ SCSS์ฒ๋ผ ํธ๋์ค์ปดํ์ผ(Source-to-Source Compile)์ด ํ์ํ๋ฐ, ๊ทธ ํธ๋์ค์ปดํ์ผ๋ฌ๊ฐ babel์ด๋ค.
โ๏ธ ์ปดํฌ๋ํธ๋ช ์ ๋ฐ๋์ capitalize์ฌ์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด babel์ด ์ผ๋ฐ HTML ์์๋ก ์ธ์ํ๋ค.
'use strict';
H3 = () => /*#__PURE__*/ React.createElement('h3', null);
h3 = () => /*#__PURE__*/ React.createElement('h3', null);
const Container = () =>
/*#__PURE__*/ React.createElement(
'div',
null,
/*#__PURE__*/ React.createElement(H3, null),
' ',
/*#__PURE__*/ React.createElement('h3', null)
);
์ฌ๋ฏธ์๊ฒ๋ v2.0์ ์ฝ๋๊ฐ ๋ฐ๋ก babel์์ ํธ๋์ค์ปดํ์ผํ ๊ฒฐ๊ณผ์ ๊ฐ๋ค.
v3.1 ๋ JSX์ค๋ฝ๊ฒ!
์ด์ ๋ถํฐ HTML์ ๋๊ฐ๋ค. (react, react-dom, babel, div#root)
let counter = 0;
const root = document.getElementById('root');
function render() {
ReactDOM.render(<Container />, root);
}
function countUp() {
counter += 1;
render();
}
const Container = () => (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={countUp}>Click me</button>
</div>
);
render();
์ด์ ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ์?
- H3, Button ์ปดํฌ๋ํธ๊ฐ ์ฌ์ฌ์ฉ์ฑ์ด ์๋ค๊ณ ํ๋จํ์ฌ ์ญ์ ํ๋ค.
- ํด๋ฆญ ์๋ง๋ค ์๋ก์ด Container ์ปดํฌ๋ํธ๋ฅผ ๋งค๋ฒ ์ ์ํ์ง ์์ ๋ฆฌ์์ค๋ฅผ ์๋๋ค. (์ด์ ๊น์ง ์๋ก Container๋ฅผ ์ ์ํ ์๋ฐ์ ์์๋ ์ด์ ๋ ์ด๊ธฐ innerText ๊ฐ์ ๋จ์ํ
Total Clicks: 0
์ด๋ผ๋ ์ฉ ๋ฌธ์์ด๋ก ํ ๋นํด๋ฒ๋ ธ๊ธฐ ๋๋ฌธ์ด๋ค.) ReactDOM.render(<Container />, root);
์ด ์ค๋ณต๋๊ธฐ ๋๋ฌธ์ render๋ผ๋ ํจ์๋ก ๊ฐ์๋ค.
v4.0 useState
function App() {
let [counter, setCounter] = React.useState(0);
const onClick = () => {
setCounter(counter + 1);
};
return (
<>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
์ด์ ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ์?
- ๊ธฐ์กด ์ฌ์ฉํ๋ counter์ counterUp ๋์ useState๋ฅผ ์ด์ฉํ์ฌ ๊น๋ํด์ก๋ค.
- Container๋ผ๋ ์ด๋ฆ์ App์ผ๋ก rename
- useState๋ฅผ ์ด์ฉํ๋ฉด ๋งค๋ฒ ๋ ๋๋งํด์ฃผ์ง ์์๋ ์ํ ๋ณํ ์ ์๋์ผ๋ก ๋ ๋๋งํ๋ค. ๋ฐ๋ผ์ render ํจ์๋ ํ์์์ด์ก๋ค. ๋ง์ง๋ง์ ReactDOM.render ํ๋ฒ๋ง ํด์ฃผ๋ฉด ๋๋ค.
- ์๋ฏธ์๋ div ๋์ Fragment ์ฌ์ฉ
v4.1 setCounter ํจ์ํ์ผ๋ก ๋ณํ
function App() {
let [counter, setCounter] = React.useState(0);
const onClick = () => {
/* setCounter(counter+1); */
setCounter((current) => current + 1);
};
return (
<>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</>
);
}
setCounter๋ฅผ ์คํํ์๋ง์ counter๋ก ๋ฐ๋ก ๋ฐ์๋๋ ๊ฒ์ด ์๋๋ผ render ํธ์ถ ์์ ๊น์ง ์ง์ฐ๋๊ธฐ ๋๋ฌธ์ unsafeํ๋ค.
const onClick = () => {
// counter=100
setCounter(counter + 1);
console.log(counter); // 100
setCounter(counter + 1);
console.log(counter); // 100
}; // render() ์ดํ์๋ counter=101
์ด ์ํฉ์ ๋๊ณ useState๊ฐ ๋น๋๊ธฐ์ ์ด๋ผ ๋ถ๋ฅธ๋ค.
const onClick = () => {
// counter=100
setCounter((counter) => counter + 1); // re-render
console.log(counter); // 101
setCounter((counter) => counter + 1); // re-render
console.log(counter); // 102
}; // render() ์ดํ์๋ counter=102 ์ ์ง.
ํจ์์ ๊ฐฑ์ ์ ์ฌ์ฉํ์.