๐ Chapter 10 : ์ปดํฌ๋ํธ ์ํคํ ์ฒ๋ฅผ ์ด์ฉํด ๊ด๋ จ ํ์ผ์ ๋ชจ์๋ผ.
๐ฏ ๊ฐ์ ธ์ค๊ธฐ์ ๋ด๋ณด๋ด๊ธฐ๋ก ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํ๋ผ.โ
- ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ๋ฐ์๋ค์ ๋ชจ๋ ์์คํ ์ ์ด์ฉํด ํ๋ก์ ํธ์์ ์ฝ๋๋ฅผ ์ฝ๊ฒ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ๋์๋ค. (Require.js, CommonJS)
- ๋ชจ๋์ ๋จ์ํ๋์๊ณ , ์ด์ ๋ ๊ฐ๋จํ import ๋ฌธ๊ณผ export ๋ฌธ์ ์ฌ์ฉํ ์ ์๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ด ๋จ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํ๋ฉด ํ๋ก์ ํธ ๋ด์ ํ์ผ ๊ฐ์ ์ฝ๋๋ฅผ ๊ณต์ ํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, ๊ฑฐ์ ๋์ผํ ๋ฌธ๋ฒ์ ์ด์ฉํด์ ์๋ฐ์คํฌ๋ฆฝํธ ์ปค๋ฎค๋ํฐ์ ๊ณต๊ฐ๋ ์ฝ๋๋ ์ฌ์ฉํ ์ ์๋ค.
- ๋ค์ ์์ ๋ ํ์ดํ ํจ์๋ก ๋ฌธ๋งฅ ํผ๋์ ํผํ๋ผ์์ ์ดํด๋ดค๋ ์์ ์ฝ๋๋ฅผ ๊ณต์ ํ๊ณ ์ถ๋ค๋ฉด ๊ฐ๋จํ
export
๋ฌธ๋ง ์ถ๊ฐํ๋ฉด ๋๋ค.
const validator = {
message: '๋ ์ ํจํ์ง ์์ต๋๋ค.',
setInvalidMessages: field => `${field}${this.message}`,
};
export { validator };
- ํจ์, ๋ณ์, ํด๋์ค๋ฅผ ๋ด๋ณด๋ผ ์ ์๋ค.
- ๋ชจ๋ ๊ฒ์ ๋ด๋ณด๋ผ ํ์๋ ์์ผ๋ฉฐ, ์ฌ๋ฌ ํจ์ ์ค ์ผ๋ถ ํจ์๋ง ๋ด๋ณด๋ด๋ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ณต๊ฐ ํจ์์ ๋น๊ณต๊ฐ ํจ์๋ฅผ ์์ฑํ ๊ฒ๊ณผ ๊ฐ๋ค.
- ๋ค์ ์ฝ๋๋ ํจ์ ๋ ๊ฐ๋ ๋ด๋ณด๋ด๊ณ , ํจ์ ํ ๊ฐ๋ ์จ๊ธฐ๋ ๊ฒฝ์ฐ์ด๋ค.
function getPower(decimalPlaces) {
return 10 ** decimalPlaces;
}
function capitalize(word) {
return word[0].toUpperCase() + word.slice(1);
}
function roundToDecimalPlace(number, decimalPlaces = 2) {
const round = getPower(decimalPlaces);
return Math.round(number * round) / round;
}
export { capitalize, roundToDecimalPlace };
- ๋ค๋ฅธ ํ์ผ์์ ํจ์๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด
import
ํค์๋๋ฅผ ์์ฑํ๊ณ ๋ถ๋ฌ์ค๋ ค๋ ํจ์๋ฅผ ์ค๊ดํธ ์์ ์์ฑํ๋ค. - ๊ทธ ๋ค์ ๊ฐ์ ธ์ฌ ํ์ผ์ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋๋ฐ, ํ์ฌ ํ์ผ์ ๊ธฐ์ค์ผ๋ก ์๋ ๊ฒฝ๋ก๋ก ์์ฑํ๋ค.
import { capitalize, roundToDecimalPlace } from './util';
function giveTotal(name, total) {
return `${capitalize(name)}๋, ํฉ๊ณ๋ ${roundToDecimalPlace(total)} ์
๋๋ค.`;
}
giveTotal('sara', 10.3333333);
// "Sara๋, ํฉ๊ณ๋ 10.33์
๋๋ค."
export { giveTotal };
- ๋ด๋ณด๋ด๊ธฐ๋ ํจ์๋ง ๊ฐ๋ฅํ ๊ฒ์ด ์๋๊ณ , ๋ณ์์ ํด๋์ค๋ ๋ด๋ณด๋ผ ์ ์๋ค.
const PI = 3.14;
const E = 2.71828;
export { E, PI };
- ๋ด๋ณด๋ด๊ธฐ์ ๊ฐ์ ธ์ค๊ธฐ๋ ํด์ฒด ํ ๋น๊ณผ ๊ฑฐ์ ๋์ผํ ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ค.
- ๊ฐ์ ธ์ค๊ธฐ ํญ๋ชฉ์ ๋ชจ๋ ๊ฐ์ฒด์ ์์ฑ์ผ๋ก ๊ด๋ฆฌํ๋ฉด ๋ณ์๋ช ์ผ๋ก ๋ชจ๋ ๊ฒ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- ํด์ฒด ํ ๋น์ ๋ฌธ๋ฒ๊ณผ ์กฐ๊ธ ๋ค๋ฅธ ์ ์ ๋ณํ(
*
)๋ฅผ ์ด์ฉํด์ ๋ชจ๋ ํจ์๋ฅผ ๋ถ๋ฌ์ค๊ณ ๋ณ์๋ช ์ ์ง ์ ํ ์ ์๋ค. - ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ฒด์ ์ํ ํจ์์ฒ๋ผ ํธ์ถํ ์ ์๋ค.
import * as utils from './util.js';
function greet(name) {
return `Hello, ${utils.capitalize(name)}`;
}
console.log(greet('seungmin'));
// Hello, Seungmin
export { greet };
- ์๋์ ๊ฐ์ด ์ ์ธํ ๊ฐ์ฒด๋ฅผ ํ์ผ์ ๋์์ ๊ฐ๋ณ์ ์ผ๋ก ์ถ๊ฐํ๋ ๋์ , ๊ฐ๊ฐ์ ํจ์ ์์
export
ํค์๋๋ฅผ ์ถ๊ฐํ๋ค. - ํ์ผ ๋๋ถ๋ถ์ ๊ฐ์ฒด๋ฅผ ์ถ๊ฐํ ํ์๊ฐ ์์ผ๋ฏ๋ก ์ฝ๋๊ฐ ํจ์ฌ ๋ ์ฌ์์ง๋ค.
function getPower(decimalPlaces) {
return 10 ** decimalPlaces;
}
export function capitalize(word) {
return word[0].toUpperCase() + word.slice(1);
}
export function roundToDecimalPlace(number, decimalPlaces = 2) {
const round = getPower(decimalPlaces);
return Math.round(number * round) / round;
}
- ์ฝ๋๋ฅผ ๋ถ๋ฆฌํ ์ ์์ผ๋ ๋จ์ผ ์ง์ ์ ์ ๊ฐ์ง ํ์ผ์ ์์ฃผ ๋ง๋ค๊ฒ ๋ ๊ฒ์ด๊ณ , ๋ ์ค์ํ ํจ์๊ฐ ์๊ธธ ์๋ ์๋ค.
- ์ด๋ ํด๋น ํ์ผ์ ๋ด๋ณด๋ด๊ธฐ ๊ธฐ๋ณธ๊ฐ(
export default
)์ ์ ์ธํ ์ ์๋ค. - ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ ธ์ค๊ธฐ ๊ณผ์ ์ด ์ข ๋ ์งง์์ง๋ค.
import { capitalize } from './util.js';
export function parseRegion(address) {
const region = address.state || address.providence || '';
return region.toUpperCase();
}
export function parseStreet({ street }) {
return street.split(' ')
.map(part => capitalize(part))
.join(' ');
}
export default function normalize(address) {
const street = parseStreet(address);
const city = address.city;
const region = parseRegion(address);
return `${street} ${city} ${region}`;
}
normalize()
ํจ์๋ฅผ ๊ฐ์ ธ์ฌ ๋๋ ์ค๊ดํธ๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.- ์ค๊ดํธ๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ๋ด๋ณด๋ด๊ธฐ ๊ธฐ๋ณธ๊ฐ๋ง ๊ฐ์ ธ์จ๋ค.
- ํจ์ ์ด๋ฆ์ ๋๊ฐ์ด ํ ํ์๋ ์๋ค.
- ๋ด๋ณด๋ด๊ธฐ ๊ธฐ๋ณธ๊ฐ์ ์ํ๋ ๋ณ์๋ช ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๋ค.
- ํ์ง๋ง ๊ฐ๋ ์ฑ์ ์ํด ๊ฐ์ ์ด๋ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
import normalize from './address.js';
function getAddress(user) {
return normalize(user.address);
}
export default getAddress;
- ๋ด๋ณด๋ด๊ธฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ํด์ง ํจ์์ ํจ๊ป ๋ค๋ฅธ ํจ์๋ ๊ฐ ์ ธ์์ผ ํ๋ ๊ฒฝ์ฐ์๋
import
๋ฌธ์ ํผํฉํ ์ ์๋ค.
import normalize, { parseRegion } from './address.js';
function getAddress(user) {
return normalize(user.address);
}
export function getAddressByRegion(users) {
// ... ์๋ต
}
getAddressByRegion(bars);
// {NY: ["1120 Manhattan Ave Brooklyn NY"]}
- ๊ฐ์ ธ์ค๊ธฐ ๊ธฐ๋ณธ๊ฐ์ ํนํ ํด๋์ค๋ฅผ ๋ถ๋ฌ์ฌ ๋ ์ ์ฉํ๋ค.
- ํ ๊ฐ์ ํ์ผ์๋ ํ ๊ฐ์ ํด๋์ค๋ง ๋๋ ๊ฒ์ด ์ข์ผ๋ฏ๋ก ๋ค๋ฅธ ์ฝ๋๋ฅผ ๋ด๋ณด๋ผ ๋งํ ์์ ๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
import { capitalize } from './util.js';
export default class Address {
constructor(address) {
this.address = address;
}
normalize() {
const street = this.parseStreet(this.address);
const city = this.address.city;
const region = this.parseRegion(this.address);
return `${street} ${city}, ${region}`;
}
parseStreet({ street }) {
return street.split(' ')
.map(part => capitalize(part))
.join(' ');
}
parseRegion(address) {
const region = address.state || address.providence || '';
return region.toUpperCase();
}
}
๐ฏ npm์ผ๋ก ์ปค๋ฎค๋ํฐ ์ฝ๋๋ฅผ ๋์ด์๋ผ.โ
- npm(node package manager)(Node ํจํค์ง ๊ด๋ฆฌ์)์ด๋ผ๋ ๋๊ตฌ๋ฅผ ์ด์ฉํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋๋ฅผ ์์ ์ ํ๋ก์ ํธ์ ์ง์ ๋ด๋ ค๋ฐ๊ณ , ๋ฒ์ ์ ๊ด๋ฆฌํ๊ณ , ์ต์ํ ๊ท์น์ ๋ฐ๋ผ ๊ฐ๋ณ ํ์ผ์์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ ์ฌ์ฉํ ์ ์๋ค.
- ๋ฌผ๋ก npm ๋ง๊ณ ํ์ด์ค๋ถ์์ ๋ง๋ , yarn์ ์ฌ์ฉํด npm์ ๋์ฒดํด ์ฌ์ฉํ ์ ์๋ค.
- npm์ ๋๋ถ๋ถ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์ฌ์ฉํ์ง๋ง, ๊ทธ ์ธ์๋ ํ๋ก์ ํธ์ ๋ฉํ๋ฐ์ดํฐ๋ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ์ค์ ํ๊ณ , ๋ช ๋ ฌ์ค ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๊ณ , ๋ค๋ฅธ ์ฌ๋๋ค์ด ์ธ ์ ์๋๋ก ํ๋ก์ ํธ๋ฅผ ๊ฒ์ํ ์๋ ์๋ค.
- npm์ ์ฌ์ฉํ๋ ค๋ฉด Node.js๋ฅผ ์ค์นํด์ผ ํ๋ค.(Node.js๋ฅผ ์ค์นํ๋ฉด npm๋ ์ค์น๋๋ค.)
- ๊ทธ ํ ํ๋ก์ ํธ๋ฅผ ์ด๊ธฐํํ๊ธฐ ์ํด
npm init
์ ์คํํด ์ค๋ค. npm init
๋ช ๋ น์package.json
ํ์ผ์ ์์ฑ์ ๋์์ฃผ ๋ ๊ตฌ์ฑ ๋๊ตฌ๋ฅผ ์คํํ๋ค.package.json
ํ์ผ์๋ ์ด๋ฆ, ์ค๋ช , ๋ผ์ด์ ์ค ๋ฑ๊ณผ ๊ฐ์ ํ๋ก์ ํธ์ ๋ฉํ๋ฐ์ดํฐ ์ ๋ณด๋ฟ ์๋๋ผ, ๋ชจ๋ ์ธ๋ถ ์์กด์ฑ ์ฝ๋๋ ํฌํจ๋์ด ์๋ค.npm init
์ ๋จ์งpackage.json
ํ์ผ๋ง์ ์์ฑํ๊ณ ๋ค๋ฅธ ์จ๊ธด ํ์ผ์ด๋ ๋๋ ํฐ๋ฆฌ๋ ์์ฑํ์ง ์๋๋ค.
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
package.json
ํ์ผ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ฅ ์ค์ํ ์ง์ ์ ์ผ๋ก ์ธ๋ถ ์์กด์ฑ์ ๋ํ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๊ณณ์ด๊ธฐ๋ ํ๋ค.npm
์ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ถ ์ ์์ ๋ฟ๋ง ์๋๋ผ ์ฝ๋๋ฅผ ๊ณต์ ํ ๋๋ ์ฌ์ฉํ ์ ์๋ค.- ๋ํ, ๋ค์ด๋ก๋ ์, ์์ ๋์ง ์์ ๋ฒ๊ทธ์ ์, ๋ฒ์ ๋ฑ์ ๋ํ ์ ๋ณด๋ฅผ ์ถ์ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
- ์กฐ์ฌํด ๋ณด๊ณ , ์ฝ๋๋ฅผ ๊ฐ์ ธ์์ ์ธ ๋งํผ ๋ง์กฑ์ค๋ฝ๋ค๋ฉด
npm install --save [์ํ๋ ํจํค์ง]
๋ช ๋ น์ ์คํํด ํ๋ก์ ํธ์ ์ค์นํ๋ค. --save
ํ๋๊ทธ๋ ๋ฐ๋์ ์จ์ผ ํ๋ ๊ฒ์ ์๋์ง๋ง ์ต๊ด์ด ๋๋ฉด ์ข๋ค.npm install
์ ํ๋ฉด ํ๋ก์ ํธ์node_modules
๋๋ ํฐ๋ฆฌ๊ฐ ์๋ ๊ฒฝ์ฐ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ ์ฑํ๊ณ ํจํค์ง๋ฅผ ๋ด๋ ค๋ฐ๋๋ค.- ๊ทธ๋ค์์๋ ์ค์นํ๋ ํจํค์ง์ ๋ฒ์ ๋ฒํธ๋ก
package.json
ํ์ผ์ ๊ฐฑ์ ํ๋ค. - ๋์ผ๋ก, ์ค์นํ๋ ์ฝ๋์ ๋ฒ์ ์ ๋ํ ์ธ๋ถ ์ ๋ณด๋ฅผ ๋ด์
package-lock.json
ํ์ผ์ ์์ฑํ๋ค. - ๊ฐฑ์ ๋
package.json
ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ผ๋ฉฐ,dependencies
ํ๋๊ฐ ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.20"
}
}
- ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ import ๋ฌธ์ ์ฌ์ฉํ์ฌ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- ํ์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๊ธฐ ๋๋ฌธ์ ๊ฒฝ๋ก๋ ์์ฑํ์ง ์์๋ ๋๋ค.
./src/merge.js
import lodash, { fromPairs } from 'lodash';
export function mapToObject(map) {
return fromPairs([...map]);
}
export function objectToMap(object) {
const pairs = lodash.toPairs(object);
return new Map(pairs);
}
- ํ๋ก์ ํธ ์ด๋ ๊ณณ์์๋ ๋์ผํ ๋ฌธ๋ฒ์ผ๋ก ์ฝ๋ ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- ์ฝ๋๋ฅผ ์ฝ์ ๋ ์ด๋ค ํจ์๊ฐ ์ฝ๋๋ฒ ์ด์ค ์ธ๋ถ์์ ๊ฐ์ ธ์จ ๊ฒ์ธ์ง ์ฝ๊ฒ ํ์ธํ ์ ์๋ค.
- ์๋ ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ถ๋ฌ์จ ์ฝ๋๋ ์ธ๋ถ ์ฝ๋์ด๋ค.
- ์คํ๊ฒฝ์ ์ํ ๋น๋์์๋ ์ ์ธํด์ผ ํ๋ ์ฝ๋๋ฅผ ๋ค๋ฃฐ ๋๋
npm
์ด ๊ฐ๋ฐ ์์กด์ฑ์ ๋ค๋ฃจ๊ณ ์คํํ ์ ์๋ ๊น๋ํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค. npm install --save-dev [์ํ๋ ํจํค์ง]
๋ก--save-dev
ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ์ค์นํ ์ ์๋ค.package.json
์ ์์กด์ฑ์ ์ถ๊ฐํ๋ ํ๋๊ฐ ๋ค๋ฅด๋ค. (devDependencies
)
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.20"
},
"devDependencies": {
"prettier": "^2.1.2"
}
}
npm
์คํฌ๋ฆฝํธ๋ฅผ ์ด์ฉํด์node_modules
๋๋ ํฐ๋ฆฌ์ ์ค์นํ ํจํค์ง๋ฅผ ์คํํ ์ ์๋ค.npm run clean
์ ์คํํ๋ฉด ํ๋ก์ ํธ์ ์ค์นํPrettier
ํจํค์ง๋ฅผnpm
์ด ์คํํด ์ค๋ค.
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"clean": "prettier --tab-width=2 --write ./code/*.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^4.17.20"
},
"devDependencies": {
"prettier": "^2.1.2"
}
}
- ์ด์ ๊ฐ๋ณ ํ๋ก์ ํธ๊ฐ ํ์๋ก ํ๋ ์์กด์ฑ์ ์ ๋ฆฌํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค์ด ๋น๋ ๊ณผ์ , ์์กด์ฑ, ํจํค์ง ์ ๋ณด๋ฅผ ํ๋์ ํ์ผ์์ ํ์ธํ ์ ์๊ฒ ๋์๋ค.
๐ฏ ์ปดํฌ๋ํธ ์ํคํ ์ฒ๋ฅผ ์ด์ฉํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๋ผ.โ
- **์ปดํฌ๋ํธ ์ํคํ ์ฒ(component architecture)**๋ก ํฉ์ด์ ธ ์๋ HTML, ์๋ฐ์คํฌ๋ฆฝํธ, CSS๋ฅผ ๋ชจ์ผ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์.
- ์ค๋ซ๋์ ๊ฐ๋ฐ์๋ค์ ํ์ผ ํ์์ ๋ฐ๋ผ ๋ถ๋ฅํ๊ณค ํ๋ค. (์ต์์ ๋๋ ํฐ๋ฆฌ์ css, js, img ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ ๋ถ๋ฅ)
- ๊ทธ๋ ์ง๋ง ๊ฐ๋ฐ์ ๋๊ตฌ๊ฐ ๋ฐ์ ํ๋ฉด์ ์๋ก์ด ํจํด์ด ๋์๋๋ฐ ๋ฐ๋ก ์ปดํฌ๋ํธ ์ํคํ ์ฒ๋ผ๋ ํจํด์ด๋ค.
- ์ปดํฌ๋ํธ๋ ๊ด๋ จ ์๋ ๋ชจ๋ ์ฝ๋๋ฅผ ์กฐํฉํด ํ๋์ ๋๋ ํฐ๋ฆฌ์ ๋ด์ ๊ฒ์ด๋ค.
- ์ด๋ ๊ฒ ํ๋ฉด ์กฐ๊ฐ์ ํ๋์ฉ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์น ํ์ด์ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์๋ค.
- ์ปดํฌ๋ํธ์ ๋ฌธ์ ๋ ์๋๋ฐ ๊ฐ์ฅ ํฐ ๋ฌธ์ ๋ ๋น๋ ๋๊ตฌ์ ์์กดํ๋ค๋ ์ ์ด๋ฉฐ, ๊ทธ๋ณด๋ค ๋ํ๊ธฐ๋ ํ์ง๋ง ํ๋ ์์ํฌ์ ์์กดํ๋ค๋ ๋ฌธ์ ๋ ์๋ค.
- ๋ค์ ์์ ๋ ๋ฆฌ์กํธ๋ฅผ ์ฌ์ฉํ ์ปดํฌ๋ํธ ์ํคํ ์ฒ์ด๋ค.
- ์ปดํฌ๋ํธ ์ํคํ ์ฒ๋ฅผ ์ด์ฉํ๋ฉด ๊ฐ๋จํ ํจํค์ง ํ๋์ ๋ชจ๋ ๊ฒ์ ๊ฒฐํฉํ ์ ์๋ค.
import React from 'react';
import './Copyright.css';
export default function CopyrightStatement() {
const year = new Date().getFullYear();
return (
<div className="copyright">
Copyright {year}
</div>
);
}
return
๋ฌธ์ ๋งํฌ์ ์ด ์๊ณ , CSS ํด๋์ค๋className
์ ์์ฑ๋์ด ์๋ค.- ์ ์ฝ๋๋ ๋ฆฌ์กํธ ํ๋ ์์ํฌ์ ์ผ๋ถ์ธ
JSX
๋ผ๊ณ ๋ถ๋ฅด๋ ํน๋ณํ ๋งํฌ์ ์ด๋ค. - ์ปดํฌ๋ํธ์ ๊ฒฝ๋ก๋
src/components
๋๋ ํฐ๋ฆฌ์ ๋ด๊ฒจ์๋ค. - ๋ํ, ๊ฒฐ๊ณผ์ ์ผ๋ก ์ปดํ์ผ๋ ์ฝ๋๊ฐ ๋ด๊ธฐ๋
public
๋๋ ํฐ๋ฆฌ๋ ์๋ค. - ๋ธ๋ผ์ฐ์ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฃฐ ์ ์๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ๊ฒ์ ๊ฒฐ๊ตญ ๋ ๊ฐ๋จํ ์ปดํฌ๋ํธ๋ก ๊ฒฐํฉ๋๋ค.
components
๋๋ ํฐ๋ฆฌ๋ ๋ค๋ค์ผ ํ ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ด๊ณ ์๋ค.- ๊ฐ ์ปดํฌ๋ํธ๋ ๊ฐ๋ณ ๋๋ ํฐ๋ฆฌ์ ๋๋์ด ์๋ค.
- ๋๋ ํฐ๋ฆฌ ์ด๋ฆ์ด ๋๋ฌธ์๋ก ์์ํ๋ ๊ฒ์ ๋ฆฌ์กํธ์์ ์ฌ์ฉํ๋ ์ปจ๋ฒค์ ์ด๋ค.
- ์ด๋ ๊ฒ ๋ถํ์ํ ์ปดํฌ๋ํธ๋ฅผ ์ญ์ ํ๊ฑฐ๋ ์ฎ๊ธฐ๊ณ ์ถ์ ๋, ๋๋ ํฐ๋ฆฌ ์ ์ฒด๋ฅผ ์ญ์ ํ ์ ์๊ณ , ๋ถํ์ํ CSS๊ฐ ์ด๋๊ฐ ๋จ์์๋ ๊ฒ์ ๊ฑฑ์ ํ์ง ์์๋ ๋๋ค.
- ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ค์ด์ผ ํ๋ค. ์ฆ, ์ต๋ํ ํ๋ ์ฝ๋ฉํ๋ ์ค์ ์ด ์์ด์ผ ํ๋ค.
- ํด๋ฆญํ ๋ ์ด๋ค ๋์์ด ํ์ํ์ง๋ ๋ช ์์ ์ผ๋ก ์์ฑํ์ง ์๋๋ค.
- ๋์ ํด๋ฆญํ ๋ ๋์์ ์ปดํฌ๋ํธ์ ์ฃผ์ ํ๋ค.
- ๋์์ด๋ ์์์ ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ ๊ฒ์ ๋ค๋ฅธ ํํ์ ์์กด์ฑ ์ฃผ์ ์ด๋ค. (์์กด์ฑ ์ฃผ์ ์ TIP 32 ํ ์คํธํ๊ธฐ ์ฌ์ด ํจ์๋ฅผ ์์ฑํ๋ผ ์ฐธ๊ณ )
import React from 'react';
import './IdeaButton.css';
import idea from './idea.svg';
export default function IdeaButton({ handleClick, message }) {
return (
<button className="idea-button" onClick={handleClick}>
<img className="idea-button_icon" src={idea} alt="idea icon" />
{message}
</button>
);
}
- ๋ฆฌ์กํธ์์๋ ์ฃผ์ ๋ ์์กด์ฑ์ ํจ์์ ์ธ์๋ฅผ ํตํด ์ ๊ทผํ ์ ์๋ค.
- ๋ํ, ํด์ฒด ํ ๋น์ ์ด์ฉํด์ ๊บผ๋ด์ฌ ์ ์๋ค.
- ๋ฒํผ์ ๋ฉ์์ง๋ ์ฃผ์ ๋ ๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ํ์๋๋ค.
- ์ค๊ดํธ๋ ํ ํ๋ฆฟ ๋ฌธ๋ฒ์ด๊ณ , ๋ณ์ ์ ๋ณด๋ฅผ ๊ฐ์ธ๊ณ ์๋ค.
- ์๋ ์์ ๋ ํ์ด์ง๋ฅผ ๋ง๋๋ ์ฝ๋๋ก ์ด ๊ฒฝ์ฐ ํ์ด์ง๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ์ด๋ค.
import React from 'react';
import './App.css';
import IdeaButton from './components/IdeaButton/IdeaButton';
import Copyright from './components/Copyright/Copyright';
function logIdea() {
console.log('์๋
ํ์ธ์! ์น ๋ฏผ์
๋๋ค!');
}
export default function App() {
return (
<div className="main">
<div className="app">
<IdeaButton
message="๋ํํ
์ข์ ์๊ฐ์ด ์์ด!"
handleClick={logIdea}
/>
</div>
<footer>
<Copyright/>
<IdeaButton
message="์ ๋ ์ข์ ์๊ฐ์ด ์์ด์!"
handleClick={logIdea}
>
</footer>
</div>
);
}
- ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ณ ๋ค๋ฅธ ๋ชจ๋ ์กฐ๊ฐ์ ํฌํจํ๋ฉฐ ๋ชจ๋ ๊ฒ์ ๊ฒฐํฉํ๋ค.
- ํ๋์ ๋ ผ๋ฆฌ์ ์ธ ์ฅ์์ ๋ชจ๋ ๊ฒ์ด ๋ชจ์ฌ ์์ ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฃจ๋ ๊ฒ์ด ์ ๋ง ๊ฐ๋จํ๋ค.
- ์ด์ฒ๋ผ ์ปดํฌ๋ํธ ์ํคํ ์ฒ๋ ์ง๊ด์ ์ผ๋ก ์ดํดํ๊ธฐ ์ฝ๋ค.
- ๊ด๋ จ๋ ํ์ผ์ ํ๊ณณ์ ๋ชจ์ผ๋ ๊ฒ์ด๋ค.
- ์ ์ผํ ์ด๋ ค์์ ๋ชจ๋ ๊ฒ์ ์ฐ๊ฒฐํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค๋ ์ ์ด๋ค.
๐ฏ ๋น๋ ๋๊ตฌ๋ฅผ ์ด์ฉํด ์ปดํฌ๋ํธ๋ฅผ ๊ฒฐํฉํ๋ผ.โ
- ๊ธฐ๋ณธ์ ์ธ ๋น๋ ํ๋ก์ธ์ค๋ฅผ ๊ตฌ์ถํ๊ธฐ์ ์์์ ์ด์ ํ์์ ์ดํด๋ดค๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋จ์ํ๊ฒ ๋ง๋๋ ๋ฒ์ ์ ์ค๋นํ๋ค.
- ๊ธฐ๋ณธ์ ์ธ ์ปจํ ์ด๋ ์ปดํฌ๋ํธ
import React from 'react';
import Copyright from './components/Copyright/Copyright';
function App() {
return (
<div className="main">
<footer>
<Copyright />
</footer>
</div>
);
}
export default App;
Copyright
์ปดํฌ๋ํธ
import React from 'react';
function Copyright() {
const year = new Date().getFullYear();
return (
<div className="copyright">
Copyright {year}
</div>
);
}
export default Copyright;
- ์ด ํ์ผ๋ค์ด ๋จ์ํ๊ธฐ๋ ํ์ง๋ง ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ์คํํ ์๋ ์๋ค.
- ์คํํ ์ ์๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋ค๊ณ ํ๋๋ผ๋ ๊ตฌํ ๋ธ๋ผ์ฐ์ ์์๋ ์คํ์ด ๋ถ๊ฐ๋ฅํ๋ค.
import
๋ฌธ,export
๋ฌธ ๋ฑ์ ES6 ๋ฌธ๋ฒ๊ณผ JSX๋ก ์์ฑํ ์ฝ๋๋ฅผ ๋ธ๋ผ์ฐ์ ์ ํธํ๋๋ ์ฝ๋๋ก ๋ฐ๊ฟ ์ ์๋ ๋๊ตฌ๊ฐ ํ์ํ๋ค.- ์ด ๋๊ตฌ๋ ๋ฐ๋ฒจ(Babel)๋ก ์ต์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ธ๋ผ์ฐ์ ์์ ์คํ ๊ฐ๋ฅํ ์ฝ๋๋ก ๋ณํํ ์ ์๋ค. (์ฐธ๊ณ )
- ๋ฐ๋ฒจ์ ES6 ์ดํ์ ๋ฌธ๋ฒ์ผ๋ก ์์ฑํ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ณํํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, ์์ง ๋ ผ์ ๋จ๊ณ์ ์๋ ๋ฌธ๋ฒ๋ ์ฌ์ฉํ ์ ์๋๋ก ๊ตฌ์ฑํ ์ ์๋ค.
- ๋ฐ๋ฒจ์ ๋ช
๋ น์ค ์ธํฐํ์ด์ค์ ํจ๊ป ES6 ์ดํ์ ๋ฌธ๋ฒ์ ๋ณํํ ๋ ํ์ํ
@babel/preset-env
, ๋ฆฌ์กํธ ์ฝ๋๋ฅผ ๋ณํํ๊ธฐ ์ํ@babel/preset-react
๋ฅผ ์ค์นํ๋ค.
$ npm install --save-dev @babel/cli @babel/preset-env @babel/preset-react
- ๋ค์์ผ๋ก ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ๋ด๊ธฐ ์ํด
.babelrc
ํ์ผ์ ์ค์ ํ๋ค. - ์ด ํ์ผ์ ๋ฐ๋ฒจ์ด ๋ค๋ฃฐ ์ฝ๋์ ์ข ๋ฅ์ ๋ณํ ๋ฐฉ๋ฒ์ ์ง์ ํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
env
๋ฅผ ๋ณด๊ณ ES6 ์ฝ๋๊ฐ ์๋ค๋ ๊ฒ์ ์ ์ ์๊ณ ,react
๋ฅผ ๋ณด๊ณ ๋ฆฌ์กํธ ์ฝ๋๋ ๋ณํํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
package.json
ํ์ผ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํ๋ฉด ์ปดํ์ผ ์ค๋น๊ฐ ๋๋๋ค.- ์ปดํ์ผํ ๊ฒฐ๊ณผ๋ ํ๋๋ก ์ถ๋ ฅ๋์ด
build
๋๋ ํฐ๋ฆฌ์bundle.js
๋ก ์ ์ฅ๋๋ค. - ์์ฑ๋
package.json
ํ์ผ์ ๋ค์๊ณผ ๊ฐ๋ค.
package.json
{
"name": "test",
"version": "1.0.0",
"description": "Chapter 10",
"main": "index.js",
"scripts": {
"build": "babel src/index.js -o build/bundle.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@babel/cli": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
}
}
index.html
ํ์ผ ์์
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>test</title>
</head>
<body>
<div id="root">
</div>
<script src="./build/bundle.js"></script>
</body>
</html>
- ๋ธ๋ผ์ฐ์ ์์ ์ปดํ์ผ๋
bundle.js
๋ฅผ ์คํํ๋ ค๊ณ ํ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๋ฐ, ๋ฐ๋ฒจ์ ์ฝ๋๋ฅผ ๋ณํํ์ง๋ง ๊ฐ์ ธ์ค๊ธฐ์ ๋ด๋ณด๋ด๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ **๋ชจ๋ ๋ก๋(module loader)**๋ ๋ด์ฅ๋์ด ์์ง ์๋ค. - ๋ชจ๋ ๋ก๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ์นํฉ(webpack)์ ์ฌ์ฉํ๋ค.(์ฐธ๊ณ )
- ์นํฉ์ ์ด์ฉํ๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ ๋ณํฉ๋ฟ๋ง ์๋๋ผ CSS์ Sass ์ฒ๋ฆฌ, ์ด๋ฏธ์ง ๋ณํ๋ ํด๊ฒฐํ ์ ์๋ค.
- ์นํฉ์์๋ ๋ก๋(loader)๋ผ๊ณ ๋ถ๋ฅด๋ ๋ฐฉ๋ฒ์ ์ด์ฉํด ํ์ผ ํ์ฅ์์ ๋ฐ๋ผ ํ์ํ ๋์์ ์ ์ธํ ์ ์๋ค. (๋ค์ํ ํ์ผ ํ์์ ๋ค๋ฃฐ ์ ์๋ค.)
- ์นํฉ์ ์คํํ๋ ค๋ฉด ์ค์น๋ฅผ ํด์ผ๋๊ณ , ์นํฉ์ ์ํ ๋ฐ๋ฒจ ๋ก๋๋ ์ค์นํด์ผ ํ๋ค.
- ๋ฐ๋ฒจ๋ก ์ฝ๋๋ฅผ ์ปดํ์ผํ๋ ๊ฒ์ ๋ธ๋ผ์ฐ์ ์์ ์คํ ๊ฐ๋ฅํ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ ๊ณผ์ ์ด๋ฉฐ, ์ด๋ฅผ ์ํด์
babel-loader
๊ฐ ํ์ํ๋ค.
$ npm install --save-dev babel-loader webpack-cli
- ๊ทธ๋ฐ ๋ค์
webpack.config.js
ํ์ผ์ ์์ฑํ๋ค. - ์ด ํ์ผ์๋ ์๋ณธ ์ฝ๋์ ์ง์ ์ ๊ณผ ์ปดํ์ผ์ด ์๋ฃ๋ ํ์ผ์ด ์ถ๋ ฅ๋ ๊ฒฝ๋ก๋ฅผ ์ ์ธํ๋ค.
- ๋ค์์ผ๋ก ์นํฉ์ด ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง๋ ์ค์ ํ๋ค.
- ์นํฉ์ ์ ๊ท ํํ์์ ์ฌ์ฉํด ๋ก๋๋ง๋ค ์ฒ๋ฆฌํด์ผ ํ ํ์ผ์ ์ ํ๋ค.
- ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ ํ์ฅ์๊ฐ .js์ธ ํ์ผ๋ง ์ฒ๋ฆฌํ ๋ ค๊ณ ์ค์ ํด์ค๋ค.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.js/,
use: 'babel-loader',
},
],
},
output: {
filename: 'build/bundle.js',
path: path.resolve(__dirname),
},
};
- ๋ง์ง๋ง ๋จ๊ณ๋ ์นํฉ์ ์คํํ๊ธฐ ์ํด
package.json
์คํฌ๋ฆฝํธ๋ฅผ ์์ ํ๋ค. - ์นํฉ์ ์ค์ ํ
webpack.config.js
ํ์ผ์ ํ์ธํ๊ธฐ ๋๋ฌธ์ ๋ณ๋์ ํ๋๊ทธ๋ ์ธ์๊ฐ ํ์ํ์ง ์๋ค. package.json
์์ ์คํฌ๋ฆฝํธ์์ ๋ฐ๋ฒจ์ ์คํ ํ๋ ๋ถ๋ถ์ ์์ ํด ์นํฉ์ ์ฌ์ฉํ๋๋ก ํด์ค๋ค.
"scripts": {
"build": "webpack"
},
- ์์ ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ฉด ๋ธ๋ผ์ฐ์ ์์ ์ฝ๋๊ฐ ์คํ๋๋ค.
$ npm run-script build
- ์นํฉ์ผ๋ก๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ปดํ์ผํ ์ ์์ ๋ฟ๋ง ์๋๋ผ, CSS๋ฅผ ์ปดํ์ผํ๊ณ ์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฌ์ฌ ์ ์๋ค.
Copyright.js
์ CSS๋ฅผ ๋ถ๋ฌ์จ๋ค.
import React from 'react';
import './Copyright.css';
function Copyright() {
const year = new Date().getFullYear();
return (
<div className="copyright">
Copyright {year}
</div>
);
}
export default Copyright;
- CSS ํ์ผ์ ํด์ํ๊ธฐ ์ํด
css-loader
์ ์คํ์ผ์ ํ์ด์ง์<head>
์์์ ์ฃผ์ ํ ๋ ์ฌ์ฉํ๋style-loader
์ด๋ค.
$ npm install --save-dev css-loader style-loader
webpack.config.js
์style-loader
๋ฅผ ๋จผ์ ์ถ๊ฐํ๊ณ ๋์css-loader
๋ฅผ ์ถ๊ฐํ๋ค.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.js?/,
use: 'babel-loader',
},
],
},
output: {
filename: 'build/bundle.js',
path: path.resolve(__dirname),
},
};
npm run-script build
๋ฅผ ์คํํ ๋คindex.html
์ ํ์ธํ๋ค.- ๋ง์ง๋ง ๋จ๊ณ๋ ์ด๋ฏธ์ง๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ผ๋ก ์ด๋ฏธ์ง๋ ์ปดํ์ผํ์ง ์๋๋ค.
- ๋์ ์ ์นํฉ์ผ๋ก ํ์ผ์ ์ฎ๊ธฐ๊ณ ๊ณ ์ ํ ์ด๋ฆ์ผ๋ก ํ์ผ๋ช ์ ๋ฐ๊พผ๋ค.
- ์นํฉ์ ๋งํฌ์ ์ ์๋ ๊ฒฝ๋ก๋ฅผ ํ์ผ์ด ์ฎ๊ฒจ์ง ๊ฒฝ๋ก๋ก ์๋์ผ๋ก ๋ฐ๊ฟ์ค๋ค.
- ์ด๋ฏธ์ง์ ํน๋ณํ ์กฐ์์ ํ์ง ์์ผ๋ฏ๋ก
file-loader
๋ฅผ ์ฌ์ฉํด์ ํ์ผ์ ์ฎ๊ธฐ๊ณ ๊ฒฝ๋ก๋ฅผ ๊ฐฑ์ ํ๋ค. - ์ด๋ฒ์๋ ๋ก๋๋ฅผ ๋จ์ํ ์ ์ธํ์ง ์๊ณ , ๋ก๋์ ์ต์ ์ ์ ๋ฌํ๋ค. ์ฆ, ๊ฐ์ฒด๋ฅผ ๋ด์ ๋ฐฐ์ด์ ์ ๋ฌํ๋ ๊ฒ์ด๋ค.
- ๊ฐ์ฒด์๋ ๋ก๋์ ์ค์ ์ต์ ์ด ํฌํจ๋๋ค.
- ํ์ํ ์ต์ ์ ์ด๋ฏธ์ง๋ฅผ ์ฎ๊ธธ ๋๋ ํฐ๋ฆฌ๋ฟ์ด๋ค.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.svg?/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'build/',
},
},
],
},
// ์๋ต..
],
},
// ์๋ต..
};
๐ฏ CSS ์ ๋๋ฉ์ด์ ์ ํ์ฉํ๋ผ.โ
- ๊ฐ๋จํ ์ ๋๋ฉ์ด์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋์ CSS๋ก ๋์ฒด๋๊ณ ์๋ค.
- ๊ธฐ๋ณธ ์์ ํ์ผ์
./src/css
ํด๋ ์ฐธ๊ณ - ๊ฐ์ฅ ๋จผ์ ์ฐ์ธก ๋ฉ๋ด๋ฅผ ์จ๊ธด๋ค.
.menu
ํด๋์ค์ ์์ฑ์ ์ถ๊ฐํ๋ค.
transform: translateX(calc(300px + 4em + 2px));
transform: translateX
์์ฑ๊ณผ ๊ฐ์ ๊ฐ์ธ๊ณ ์๋div
๋ฐ์ผ๋ก ํ์ด์ง๋ฅผ ์ด๋์ํค๊ณ ์ ๋ณด์ด๊ฒ ๋ง๋ ๋ค.- ๋ฉ๋ด์ ๋๋น(width)์ ์์ชฝ ์ฌ๋ฐฑ(padding)๊ณผ ์ธ๊ณฝ์ (border)์ ํฌ๊ธฐ๋ฅผ ๋ํ๋ค.
- ๋ฉ๋ด๋ฅผ ์จ๊ธด ๋ค ๋ค์์ผ๋ก ํธ๋์ง์ (transition)(์ ํ)์ ์ถ๊ฐํ๋ค.
- CSS ํธ๋์ง์ ์ ์์ฑ ๋ณํ๋ฅผ ์ด์ฉํ ์ ๋๋ฉ์ด์ ์ด๋ค. ์ฆ, ์ ๋๋ฉ์ด์ ์ ๊ฐ์ ์ด๋ฆ์ ๊ฐ์ง ๋ ์์ฑ ๊ฐ์ ์๊ฐ์ ์ธ ์ ํ์ผ ๋ฟ์ด๋ค.
- ์์ฑ์ ๋ณ๊ฒฝํ๊ธฐ ์ํด์๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๋ฒํผ์ ํด๋ฆญ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํด ์ค๋ค.
const sidebar = document.getElementById('sidebar');
document.getElementById('show')
.addEventListener('click', () => {
sidebar.classList.toggle('display');
});
- ๋ค์์ผ๋ก ์คํ์ผ์ํธ์
.menu.display
ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ค.
.main {
/* ์๋ต.. */
transform: translateX(calc(300px + 4em + 2px));
}
.menu.display {
transform: translateX(0);
}
- ๋ฒํผ ํด๋ฆญ ์ ์ ๋๋ฉ์ด์ ์ด ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- CSS ํธ๋์ง์ ์ ์ต์ด์ ์์ฑ๊ฐ์์ ๋ง์ง๋ง ์์ฑ๊ฐ์ผ๋ก ๋ฐ๋ ๋ ํ์ด์ง๊ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง๋ฅผ ์๋ ค์ฃผ๋ ๋ช ๋ น์ ๋ชจ์์ด๋ค. (MDN ์ฐธ๊ณ )
- ๋จผ์
transition-property
์ ํธ๋์ง์ ์ ์ ์ฉํด์ผ ํ ์์ฑ์ ์ ๋ ฅํ๋ค. - ์ด ๊ฒฝ์ฐ
transform
์์ฑ๋ง ์ ๋๋ฉ์ด์ ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ์์ฑ๊ฐ์ผ๋กtransfrom
์ ์ ๋ ฅํ๋ค. - ๋ค์์ผ๋ก
transition-duration
์์ฑ์ ์ ๋๋ฉ์ด์ ์ง์ ์๊ฐ์ ์ ๋ ฅํ๋ค. - ๋์ผ๋ก, ํธ๋์ง์
์ด ์ด๋ป๊ฒ ๋์ํ ์ง๋ฅผ
transition-timing-function
์์ฑ์ ์ค์ ํ๋ค. (MDN ์ฐธ๊ณ )
.menu.display {
transform: translateX(0);
transition-property: transform;
transition-duration: 600ms;
transition-timing-function: linear;
}
- ํ์ฌ ์ํ๋ ๋ฉ๋ด๊ฐ ์ฌ๋ผ์ง ๋ ๋ฐ๋ก ์ฌ๋ผ์ง๋ค. ์ด ๊ฒฝ์ฐ๋ ํธ๋์ง์
์
.display
ํด๋์ค๊ฐ ์ถ๊ฐ๋๋ ๊ฒฝ์ฐ์๋ง ์ ์ธํ ๊ฒ์ด ๋ฌธ์ ์ ์์ธ์ด๋ค. - ์ด ๊ฒฝ์ฐ๋ ๊ธฐ๋ณธ์ด ๋๋
.menu
ํด๋์ค์ ํธ๋์ง์ ์ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ๋๋ค. - ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ ์ ์๋ค.
.menu {
/* ์๋ต.. */
transform: translateX(calc(300px + 4em + 2px));
transition: all 600ms linear;
}