μ²μμΌλ‘ 2μ£Όμ§λ¦¬ λ―Έμ μ μμνκ² λμμ΅λλ€. μ΄λ² λ―Έμ μ κ°κ³λΆ μλΉμ€λ₯Ό ꡬννλ κ²μ λλ€. ν λ¨μλ‘ λ―Έμ μ μννλλ° 1μ£Όμ°¨μ κ°μ κ·Έλ£ΉμΌλ‘ λ°°μ λ λΆμ΄λΌ μλ‘ λ―Έμ μ μννλλ°μ ν° νΈλ¬λΈμ μμμ΅λλ€. π
μνκ΄λ¦¬λ₯Ό μν΄ μ΅μ λ² ν¨ν΄μ μ¬μ©νμ΅λλ€. μ΅μ λ² ν¨ν΄μ μν κ°μ²΄λ₯Ό λ°ννλ κΈ°κ΄μ΄ μκ³ κ° μ»΄ν¬λνΈ λλ κ°μ²΄μμ κ·Έκ²μ ꡬλ νλ ν¨ν΄μ λλ€. ꡬλ ν κ°μ²΄μμ λ³νκ° κ°μ§λλ©΄ ꡬλ ν μμλ€μ μμμ λ‘μ§μ μ€νν©λλ€.
κ°λ¨νκ² λ§νμλ©΄ 리μ‘νΈμμ 리λμ€λ₯Ό μ¬μ©νλ κ²κ³Ό κ°μ΅λλ€. 리λμ€μμλ μνλ₯Ό ꡬλ νλ μ»΄ν¬λνΈκ° ν΄λΉ μνκ° λ³ννλ©΄ 리λ λλ§λ©λλ€. μ΄λ² λ―Έμ μμλ 리λμ€μ ννλ₯Ό λ³Έλ° μ€μμ§μ€ν μνκ΄λ¦¬ μ μ₯μλ₯Ό ꡬννμ΅λλ€.
import reducer from './reducer';
function isSameState(state, newState) {
return JSON.stringify(state) === JSON.stringify(newState);
}
function createStore(reducer) {
let listeners = [];
let state = reducer(undefined, { type: null });
function subscribe(key, callback) {
const listener = { key, callback };
listeners.push(listener);
function unsubscribe() {
listeners = listeners.filter((l) => l !== listener);
}
return unsubscribe;
}
function getState(key) {
return state[key];
}
function getChangedKeys(newState) {
return Object.keys(newState).reduce(
(changedKeys, key) =>
state[key] !== newState[key] ? [...changedKeys, key] : changedKeys,
[]
);
}
function invokeListeners(key) {
listeners.forEach((listener) => {
if (listener.key === key) {
listener.callback();
}
});
}
function notify(changedKeys) {
changedKeys.forEach((key) => {
invokeListeners(key);
});
}
function dispatch(action) {
const newState = reducer(state, action);
if (isSameState(state, newState)) {
return;
}
const changedKeys = getChangedKeys(newState);
state = newState;
notify(changedKeys);
}
function resetListeners() {
listeners = [];
}
return { subscribe, getState, dispatch, resetListeners };
}
export default createStore(reducer);
λ―Έμ μμ μ¬μ©ν storeμ λλ€. subscribeλ₯Ό μ΄μ©ν΄ ꡬλ νκ³ dispatchμ μ‘μ κ°μ²΄λ₯Ό μ λ¬ν©λλ€. κ·Έλ¦¬κ³ μ§μ ν reducerμμ μ‘μ μ λ§λ λμμ μννκ³ stateλ₯Ό λ³κ²½μν΅λλ€. λ³κ²½μ΄ κ°μ§λλ©΄ λ°λ key κ°λ€μ μλ³νκ³ κ·Έμ λ°λΌ λ±λ‘λ listenerλ₯Ό μ€νμν΅λλ€. listenerλ stateμ keyμ 맀νλλ callbackμΈλ° λ³΄ν΅ μ»΄ν¬λνΈμ render ν¨μκ° λ±λ‘λ©λλ€.
ν΄λΉ κ³Όμ μ ν΅ν΄ ꡬλ μ€μΈ μνκ° λ³κ²½λλ©΄ μ»΄ν¬λνΈμ 리λ λλ§μ λ°μμν¬ μ μμ΅λλ€.
const routes = {
'/': renderHome,
'/calendar': renderCalendar,
'/analytics': renderAnalytics,
};
function render(path) {
const renderPage = routes[path];
if (!renderPage) {
render404();
return;
}
renderPage();
}
λΌμ°ν°μ λλ΅μ μΈ κ΅¬μ‘°μ λλ€. routes κ°μ²΄μλ urlκ³Ό νμ΄μ§ λ λλ§ ν¨μλ₯Ό 맀νμμΌ νμ¬ pathκ° routesμ μλ€λ©΄ ν΄λΉ νμ΄μ§λ₯Ό λ λλ§νκ³ , μλ€λ©΄ 404 νμ΄μ§λ₯Ό 보μ¬μ€λλ€.
νμ¬λ '/'μ ν΄λΉνλ urlμμλ§ index.htmlμ μ μ‘νκΈ° λλ¬Έμ λ€λ₯Έ νμ΄μ§μμ μλ‘κ³ μΉ¨μ νκ±°λ urlλ‘ μ§μ μ κ·Όμ ν κ²½μ° μ±μ λΆλ¬μ¬ μ μμ΅λλ€. κ·Έλ κΈ° λλ¬Έμ νλ‘ νΈμλ index.htmlμ λͺ¨λ μ£Όμμ λμμμΌμ£ΌκΈ° μν΄ express μλ²λ₯Ό μΆκ°λ‘ λ§λ€μμ΅λλ€.
// app.js
const express = require('express');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 5500;
app.use('/static', express.static(path.resolve('./dist')));
app.get('*', (_req, res) => {
res.sendFile(path.resolve('./dist/index.html'));
});
app.listen(PORT, () => {
console.log('app is listening on PORT', PORT);
});
λͺ¨λ μ£Όμμ index.htmlμ λμμν€λ μλ²λ‘ λ¨μν htmlμ μ μ‘νλ μ©λλ‘ μ¬μ©λ©λλ€.
ν΄λΉ ꡬ쑰λ₯Ό λ§λ€ λ κ°κ³Όν λΆλΆμ΄ μμ΅λλ€. λ°λ‘ μ»΄ν¬λνΈ λ΄λΆμμ μμ μ»΄ν¬λνΈλ§ 리λ λλ§ μν¬ κ²½μ°μ λλ€. μ»΄ν¬λνΈ μμ μ»΄ν¬λνΈκ° μκ³ , μμ μ»΄ν¬λνΈκ° μνλ₯Ό ꡬλ μ€μ΄λΌλ©΄ ν΄λΉ μμμ μλ‘μ΄ μμμΌλ‘ κ΅μ²΄ν λ κΈ°μ‘΄μ μλ ꡬλ μ ν΄μ ν΄μΌν©λλ€.
λ―Έμ μ§ν μ΄λ°μλ μ΄λ° λΆλΆμ μκ°νμ§ λͺ»ν΄μ, μ§ν λμ€ κ΅¬μ‘°λ₯Ό λ°κΏμΌνμ΅λλ€. κ·Έλ κΈ° λλ¬ΈμΈμ§ μ€νλ°λΆμ μ§ν μν©μ΄ λλμ§λ νμμ΄ λ°μνμ΅λλ€. μ΄κΈ°μ μΆ©λΆν λ§μ λ Όμλ₯Ό νμλ€λ©΄ μ΄λ° μν©μ λ°©μ§ν μ μμμ ν λ° μ‘°κΈ μμ½μ΅λλ€.
κ²°κ³Όμ μΌλ‘λ λ€μκ³Ό κ°μ core Componentλ₯Ό λ§λ€κ³ ν΄λΉ Componentλ₯Ό μμλ°λ κ΅¬μ‘°λ‘ μ»΄ν¬λνΈλ₯Ό λ³κ²½νμ΅λλ€.
import store from '../store/store';
class Component {
constructor() {
this.childComponents = [];
this.unsubscribe = [];
this.keys = new Set();
}
subscribe(key, callback) {
this.keys.add(key);
this.unsubscribe.push(store.subscribe(key, callback));
}
getState(key) {
if (!this.keys.has(key)) {
throw new Error(`Doesn't have a key`);
}
return store.getState(key);
}
setChild(children) {
this.childComponents.push(children);
}
clearChildren() {
this.childComponents.forEach(clear);
this.childComponents = [];
}
clearChild(childComponent) {
clear(childComponent);
this.childComponents = this.childComponents.filter(
(component) => component !== childComponent
);
}
clearSelf() {
this.DOMElement.remove();
this.unsubscribe.forEach((u) => u());
this.clearChildren();
}
}
function clear(childComponent) {
childComponent.unsubscribe.forEach((u) => u());
childComponent.clearChildren();
childComponent.DOMElement.remove();
}
export default Component;
μ΄ μ½μ΄ μ»΄ν¬λνΈμ ꡬ쑰λ μ΄λ―Έ μ½λκ° μ΄λ μ λ μμ±λ μν©μμ λ§λ€μ΄μ‘κΈ° λλ¬Έμ ꡬνμ μ’ μλμ΄λ²λ¦° λλμ΄ μμ΅λλ€. μ’ λ μ μ°ν μ€κ³λ₯Ό νμ§ λͺ»ν κ² κ°μ΅λλ€.
λ°±μλλ₯Ό ꡬνν λ DAO ν¨ν΄μ μ΄μ©νμ΅λλ€. DAO(Data Access Object)λ DBμ μ κ·Όνλ κ°μ²΄λ‘ λΉμ¦λμ€ λ‘μ§μμ ν΄λΉ κ°μ²΄κ° μ 곡νλ λ©μλλ₯Ό μ΄μ©ν΄ DBμ μ κ·Όνλ ν¨ν΄μ λλ€. DAO ν¨ν΄μ μ₯μ μΌλ‘λ κ΄μ¬μ¬μ λΆλ¦¬μ μΈν°νμ΄μ€λ₯Ό μ΄μ©ν νλ‘κ·Έλλ°μ ν μ μλ€λ κ²μ λλ€.
κ°κ°μ κ΄μ¬μ¬μ λ°λΌ λ‘μ§μ λΆλ¦¬μμΌ°κΈ° λλ¬Έμ μ μ§λ³΄μμ μ©μ΄νκ³ , μΈν°νμ΄μ€λ₯Ό μ΄μ©ν ꡬνμ΄ κ°λ₯νκΈ° λλ¬Έμ κ°λ μ± μΈ‘λ©΄μμλ λ°μ΄λ©λλ€.
import {
addQuotesToString,
timeConverter,
} from '../../utils/data_transformer.js';
import pool from '../loader.js';
const promisePool = pool.promise();
async function insertHistory(history) {
try {
const [rows] = await promisePool.execute(
`INSERT INTO HISTORY (${Object.keys(history).join()})
VALUES (${Object.values(history).map(addQuotesToString).join()})`
);
return rows;
} catch (e) {
console.error(e);
}
}
.
.
.
async function deletePaymentMethodInHistory(value) {
try {
const [rows] = await promisePool.execute(
`
UPDATE HISTORY
SET paymentMethod = ""
WHERE paymentMethod = "${value}"
`
);
return rows;
} catch (e) {
console.error(e);
}
}
export default {
insertHistory,
readHistoryByYearMonth,
deleteHistoryById,
updateHistoryById,
getRecentHistory,
deletePaymentMethodInHistory,
};
ν΄λΉ ννμ²λΌ API μλ²μ DAO κ°μ²΄λ₯Ό λ§λλ‘ κ·Έκ²μ exportνλ λ°©μμΌλ‘ ꡬννμ΅λλ€. APIλ₯Ό λ΄λΉνλ λ‘μ§μ DAOκ° μ 곡νλ μΈν°νμ΄μ€λ₯Ό ν΅ν΄μ DBμ μ κ·Όν©λλ€.
connection poolμ ꡬνμ ν κ²μ μλκ³ , node js mysql ν¨ν€μ§μμ μ 곡νλ κΈ°λ₯ μ€ νλμ λλ€. μ¬μ©μ μΈ‘μμ μμ²μ λ³΄λ΄ API μλ²μ DB μ¬μ΄μμ ν΅μ μ νλ €λ©΄ μ°κ²°μ μ립ν΄μΌν©λλ€.
μ°κ²°μ μ°κ²°νλ κ²λΆν° κ·Έκ²μ μ μ§νλ κ²κΉμ§ λͺ¨λ λΉμ©μ λλ€. λ§μ½ λ€μμ μ¬μ©μλΌλ©΄ κ·Έ λΉμ©μ μμ²λ λΆλ΄μΌλ‘ λ€κ°μ΅λλ€.connection poolμ μ΄μ©νλ©΄ κ·Έλ° λΆλ΄μ μλΉ λΆλΆ λμ΄λΌ μ μμ΅λλ€.
poolμ connectionλ€μ λͺ¨μλμ κ²μ λλ€. poolμ λ±λ‘λ connectionμ μ¬μ©μλ€μ΄ νμν λλ§λ€ κ°μ Έλ€ μ°κ³ , μ¬μ© ν κ·Έκ²μ λ€μ λ°νν©λλ€. κ·Έλ κ² λλ€λ©΄ λ€μ μ°κ²°μ μ립, ν΄μ ν νμκ° μμ΄μ§κΈ° λλ¬Έμ ν¨μ¨μ± μΈ‘λ©΄μμ λμμ΄ λ©λλ€.
λ¬Όλ‘ λ―Έλ¦¬ connectionλ€μ λ§λ€μ΄λμΌ νκΈ° λλ¬Έμ κ·Έκ²μ μν μ΄κΈ° λΉμ©κ³Ό, poolμ κ΄λ¦¬νλ μΆκ°μ μΈ λΉμ©μ΄ μκΉλλ€. κ·Έλ κΈ° λλ¬Έμ μ€μ μν©μμλ μλΉμ€μ κ·λͺ¨μ λ°λΌ poolμ ν¬κΈ°μ κ·Έκ²μ νμμ±μ λν΄ μΆ©λΆν λ Όμν΄μΌ ν κ² κ°μ΅λλ€.
import pool from '../loader.js';
const promisePool = pool.promise();
async function getPaymentMethodById(id) {
try {
const [rows] = await promisePool.execute(`SELECT name FROM PAYMENT_METHOD
WHERE id = ${id}`);
return rows;
} catch (e) {
console.error(e);
}
}
async function readPaymentMethod() {
try {
const [rows] = await promisePool.execute(`SELECT * FROM PAYMENT_METHOD`);
return rows;
} catch (e) {
console.error(e);
}
}
async function insertPaymentMethod(value) {
try {
const [rows] = await promisePool.execute(
`INSERT INTO PAYMENT_METHOD (name)
VALUES ("${value}")`
);
return rows;
} catch (e) {
console.error(e);
}
}
async function deletePaymentMethodById(id) {
try {
const [rows] = await promisePool.execute(`
DELETE FROM PAYMENT_METHOD
WHERE id = ${id}
`);
return rows;
} catch (e) {
console.error(e);
}
}
export default {
readPaymentMethod,
insertPaymentMethod,
deletePaymentMethodById,
getPaymentMethodById,
};
μ΄λ² λ―Έμ μμ μ¬μ©ν DAOμ μΌλΆλΆμ λλ€. μμ§ SQL λ¬Έμ μ΅μνμ§ μμκΈ° λλ¬ΈμΌ μλ μκ² μ§λ§, μ€λ³΅μ μΌλ‘ νΉμ SQL λ¬Έμ νΈμΆμ΄ λ°λ³΅λλ€λ λλμ λ°μμ΅λλ€. μ¬λ¬ λ² λ°λ³΅λλ λΆλΆμ 곡ν΅λ λ‘μ§μΌλ‘ λ§λ€ μ μκ² λ€λ μκ°μ΄ λλλ€.
μΊ νΌ μ€ ν λΆμ ORMμ μ§μ λ§λμ ¨λλ° μ λ§ λλ¨νλ€λ μκ°μ΄ λλλ€... π
μ΄λ²μ 2μ£Ό μ§λ¦¬ λ―Έμ μ΄λΌ ν¬λ‘±κ³Ό νΈλ μ€μ λ¦¬λ·°κ° μ½λμ μΈ μΈ‘λ©΄μμλ λ§μ΄ μμμ΅λλ€. κ·Έλλ νμ μμ μ΄μ κ΄λ¦¬λ²μ΄λ, λ²μ©μ μΈ νλ‘κ·Έλλ°μ λν΄ λ§μ κ²λ€μ μ μ μμμ΅λλ€.
μ΄μλ ꡬνν΄μΌνλ κΈ°λ₯κ³Ό κ·Έκ²μ μλ£ μ‘°κ±΄μ κΈ°λ‘ν΄λλ κ² μ’μ΅λλ€. μ¬μ μ λ²κ·Έλ₯Ό μΆ©λΆν λ°©μ§ν΄μΌνκΈ° λλ¬Έμ λ§μ λ Όμλ₯Ό κ±°μ³μ μ΄μλ₯Ό μ μ€ν μμ±νλ κ² μ³μ κ² κ°μ΅λλ€. ν¬λ‘±μ λ³΄ν΅ μ¬μ©μμ μλ리μ€λ₯Ό μκ°νλ©΄μ 미리 μλΉμ€μ νλ‘μ°λ₯Ό μ μ μ΄λ΄λ¦¬λ©΄ μ΄μκ° μ μ λ‘ μκΈ΄λ€κ³ ν©λλ€. μ΄λ²μλ κ·Έμ λλ‘ κΉκ²λ ν΄λ³΄μ§ λͺ»νμ§λ§ λ€μ λ―Έμ μμλ μλν΄λ΄μΌκ² μ΅λλ€ γ γ
νκ³ λ₯Ό μμ±ν λλ§λ€ νμ λμ€λ λ§μΈ κ² κ°μ΅λλ€. μ½λλ μμ μ λμμ μΆ©λΆν νννκ³ μμ΄μΌ νλ€. μ μ ν λ³μλͺ κ³Ό ν¨μλͺ , κ·Έλ¦¬κ³ κΈ°λ₯μ λΆλ¦¬λ₯Ό μ΄μ©ν΄ μ΅λν κ°κ²°νκ³ λͺ ννκ² μμ±ν΄μΌν©λλ€. νμ μ’μ μ½λλ λ€λ₯Έ μ¬λμ΄ μ½κΈ° νΈν μ½λλΌκ³ μκ°νλλ°, μμ§λ κ·Έλ° λΆλΆμ λ―Έμν κ² κ°μ΅λλ€. μ‘°κΈ μκ°μ΄ 걸리λλΌλ νμ νλΆν ννλ ₯μ κ°μ§λ μ½λλ₯Ό μμ±νκΈ° μν΄ λ Έλ ₯ν΄μΌκ² μ΅λλ€.
νμ μ½λλ₯Ό μμ±νλ©΄μ λ€λ₯Έ μ¬λμ μ½λλ₯Ό μ°Έμ‘°νλ μΌμ΄ λ§μ΅λλ€. μ λ΅μ§λ₯Ό λ¨Όμ νΌμΉλ μ΅κ΄μ΄ μ’μ§λ μμ§λ§, μ€μ€λ‘ μκ°νλ κ²λ³΄λ€λ λ€λ₯Έ μ¬λμ μ½λλ₯Ό λ¨Όμ λ³΄κ³ ν΄λΉ μ½λμμ μλ¬Έμ μ λ¨Όμ μ°Ύλ κ²λ μ’λ€κ³ μκ°νκΈ° λλ¬Έμ μ΄λ° νλλ‘ μ½λ©μ νκ³ μμ΅λλ€. νμ§λ§ νΈλ μ€μ λ§μ λ£κ³ λ무 μμ κ΄μ μμ νμΈμ μ½λλ₯Ό μ°Έμ‘°νλ€λ μκ°λ λ€μμ΅λλ€.
νΈλ μ€λ νμΈμ μ½λλ₯Ό μ°Έμ‘°νλ κ²λ μ’μ§λ§ μΆ©λΆν μ΄ν΄λ₯Ό μ ννκ³ μ°Έμ‘°νλΌλ λ§μ νμ΅λλ€. μ΄κ²μ νμμ κ°μ‘λ νλμ μΌμΉνκΈ°μ λ³ λ¬Έμ λ μμ΅λλ€. λ¬Έμ λ κ·Έ λ€μμ λ§μ΄μμ΅λλ€. μ½λκ° μ΄λ° ν¨ν΄μ κ°μ§κ² λ μμ¬λ₯Ό 곡λΆνλΌλ λ§μ λλ€. ν΄λΉ ν¨ν΄μ΄ μμλ€λ©΄ μ΄λ€ λ¬Έμ κ° μκΈ°κ³ , κ·Έ ν¨ν΄μ΄ μ΄λ»κ² λ¬Έμ ν΄κ²°μ λμμ΄ λλμ§κΉμ§λ μκ°ν΄ λ³Έ κ²½νμ΄ λ§μ§ μμ΅λλ€. νλ‘κ·Έλλ°μ μμ¬μ μΈ μΈ‘λ©΄μμ μκ°νλ κ²λ μκ°μ νμ λνλλ° ν° λμμ΄ λ κ² κ°μ΅λλ€.
λ³νμ νμ₯μ μ μ°νκ² λμν μ μλ μ½λκ° μ’μ μ½λλΌλ λ§μ λ€μμ΅λλ€. μκ°ν΄λ³΄λ μ΄λ² μ°ν μΊ 2μ°¨ κ³Όμ ν μ€νΈμμλ μ»΄ν¬λνΈμ μ¬μ¬μ©μ±μ΄ μꡬμ¬νμ μμλ κ² λ¬Έλ λ μ€λ¦ λλ€. λ²μ©μ μΈ μΈν°νμ΄μ€λ₯Ό ꡬνν΄ κ·Έκ²μ κΈ°λ°μΌλ‘ νλ‘κ·Έλλ°μ νλ κ². νμ λ¨Έλ¦Ώμμ μ겨λ¬μΌκ² μ΅λλ€. μΆ©λΆν μμ λ¨μλ‘ κ°μ²΄μ λ©μλλ₯Ό λΆλ¦¬νκ³ μ΅λν μΆ©λμ λ°©μ§νλ μ 체μ μΈ κ΅¬μ‘°λ₯Ό μ§μμ μΌλ‘ λ μ¬λ¦¬λ©° μ½λλ₯Ό μμ±νκ² μ΅λλ€ :)
2μ£Όμ°¨ λ―Έμ μ 첫 μ£Όλ μ€κ³λ₯Ό μ€μ μΌλ‘ νλ‘κ·Έλλ°μ μ§ννμ΅λλ€. API λͺ μΈλ₯Ό μμ±νκ³ , μνκ΄λ¦¬, λΌμ°ν μ νμ μ€κ³νλ 건 μ λ§ μ¬λ―Έμμμ΅λλ€. νμ νΌμ νλ‘κ·Έλλ°μ ν λλ μ€κ³λ μ ν μκ³ μ½λμ μμ±μ λ¨Όμ μμνμλλ°, κ²½ννμ§ λͺ»νλ μλ‘μ΄ λ°©μμ μκ°μ κ΄μ κ³Ό ν΅μ°°λ ₯μ λν μ μλ μ’μ κΈ°νμμ΅λλ€.
λ€λ§ μ£Όμν΄μΌκ² λ€κ³ μκ°ν μ μ΄ νλ μλλ°, λ°λ‘ μ€κ³μ λ¬ΆμΈ μ½λμ μμ±μ λλ€. μΆ©λΆν μ μ°νμ§ λͺ»ν μ€κ³λ μ€νλ € νλ‘κ·Έλλ°μ ν΄λ₯Ό λΌμΉ μ μμ΅λλ€. κ·Έλ κΈ° λλ¬Έμ ν¨κ»νλ νμκ³Ό μ’μ μ€κ³ λ°©ν₯μ λν΄ μΆ©λΆν λ Όμλ₯Ό κ±°μ³μΌν©λλ€.
μ΄λ² λ―Έμ μ ν΅ν΄ μκ°μ μΈ μΈ‘λ©΄μμ λ§μ κ²λ€μ λ°°μΈ μ μμμ΅λλ€ γ γ
λΉμ μ κ°λ° μ€λ ₯μ νμΉκ³ μΆμ΄..