Feature
- Login
- Signup
- Main
- โ Recommend
- โ Product
- Product Detail
- Cart
(๋์ ๋ด๋น ํ์ด์ง : โ )
๋ด๊ฐ ์ ํ๊ณ ์๋์ง ๋ถ์ํ ๋, ์ฝ๋ ํ ์ค ํ ์ค ๋ฏ์ด๋ณด๋ฉฐ ์ค๋ช ํ ์ ์๋์ง ํ์ธํด๋ณด๋ฉด ๋๋ค๊ณ ํด์ฃผ์ ๋ฉํ ๋์ ์กฐ์ธ์ ๋ฐ๋ผ ์ฝ๋ ์ดํด๋ณด๊ธฐ ์์ !
Recommend ์ปดํฌ๋ํธ๋ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
์ฒ์์ SurveyWelcome ์ปดํฌ๋ํธ๋ฅผ ๋์ฐ๊ณ , ๋ค์ ๋ฒํผ์ ๋๋ ์ ๋ Survey01, Survey02, Survey03, Survey04 ์์ผ๋ก ์ปดํฌ๋ํธ ๊ต์ฒด๊ฐ ํ์ํ๋ค. ๊ทธ๋์ ๋จผ์ ๊ฐ ์ปดํฌ๋ํธ๋ฅผ survey
๋ผ๋ ๊ฐ์ฒด๋ก ๋ฌถ์ด ์ค ๋ค, ์์
์ ์์ํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.
๐ป ์ฝ๋ ํ์ค ํ์ค ๋ฏ์ด๋ณด๊ธฐ
โ๏ธ Recommend.js (๋ถ๋ชจ ์ปดํฌ๋ํธ) / render() ์ const ์ ์ธ
render() {
const survey = {
1: (
<SurveyWelcome
surveyId={this.state.surveyId}
handleNextSubmmit={this.handleNextSubmmit}
/>
),
2: (
<Survey01
surveyId={this.state.surveyId}
handleNextSubmmit={this.handleNextSubmmit}
handlePrevSubmmit={this.handlePrevSubmmit}
handleInput={this.handleInput}
/>
),
3: (
<Survey02
surveyId={this.state.surveyId}
handleNextSubmmit={this.handleNextSubmmit}
handlePrevSubmmit={this.handlePrevSubmmit}
handleInput={this.handleInput}
name={this.state.name}
/>
),
4: (
<Survey03
surveyId={this.state.surveyId}
handleNextSubmmit={this.handleNextSubmmit}
handlePrevSubmmit={this.handlePrevSubmmit}
handleInput={this.handleInput}
name={this.state.name}
/>
),
5: (
<Survey04
surveyId={this.state.surveyId}
handlePrevSubmmit={this.handlePrevSubmmit}
handleNextSubmmit={this.handleNextSubmmit}
handleCheckBox={this.handleCheckBox}
handleInput={this.handleInput}
name={this.state.name}
makeCondition={this.makeCondition}
history={this.props.history}
/>
),
};
....
}
๊ฐ ์ปดํฌ๋ํธ๋ง๋ค ํ์ํ ๋ฐ์ดํฐ, ํจ์๋ค์ ์ ๋ฌํด์ฃผ์๋ค. ์์๊ฐ ๋ค๋ฐ๋์์ง๋ง ๋ค์ ํ์ด์ง๋ก ๋์ด ๊ฐ ์ ์๋ ํจ์๋ ์๋์ ๊ฐ๋ค. โฌ๏ธ
handleNextSubmmit = surveyId => {
const newAnswer = [...this.state.answer, { id: surveyId }];
this.setState({
answer: newAnswer,
});
this.handleNextButton(surveyId);
};
handlePrevSubmmit = surveyId => {
const previousAnswer = this.state.answer.filter(previous => {
return previous.surveyId !== surveyId;
});
this.setState({
answer: previousAnswer,
});
this.handlPrevButton(surveyId);
};
handlPrevButton = id => {
this.setState({ surveyId: id - 1 });
};
handleNextButton = id => {
this.setState({ surveyId: id + 1 });
};
์ง๊ธ์ ์ ๋ ฌ๋ ๋ฏ ๋ณด์ด์ง๋ง,, ์ฒ์์ ๊ตฌ์ํ ๋๋ ์ ๋ง ๋จธ๋ฆฌ ์ํ ์ฝ๋์๋ค. ๋ฆฌํฉํ ๋ง ํ๊ธฐ ์ ์ handleNextSubmmit
ํจ์๋ฅผ concat์ผ๋ก ๊ตฌํํด์ handlePrevSubmmit
๊ฐ ๊ทธ ๋ฐ๋๋ผ๊ณ ์๊ฐํ๋ splice, slice ๋ฑ๊ณผ๊ฐ์ ๋ฉ์๋๋ง ์๊ฐํ๊ฒ ๋์๋ค. ๊ทธ๋ ๊ฒ ์๊ฐ์ ํ๋ค๊ฐ ๊ฐ์ ํ ์ฐฝ์๋๊ป ์ข ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ด ์์๊นํ๊ณ ์ฌ์ญค๋ณด์๋๋ฐ, filter ๋งค์๋๋ฅผ ์ด์ผ๊ธฐ ํด์ฃผ์
จ๋ค. filter๋ฅผ ์ฌ์ฉํ๋ค๊ณ ์๊ฐํ๋ handleNextSubmmit
ํจ์๋ concat์ด ์๋ spread ์ฐ์ฐ์๊ฐ ์๊ฐ์ด ๋์ ์ฝ๋๋ฅผ ์์ ํ์๋ค!
โ๏ธ Recommend.js (๋ถ๋ชจ ์ปดํฌ๋ํธ) / render() ์ return ๊ฐ
<div className="SurveyBox">{survey[this.state.surveyId]}</div>
์์์ ํด๋น ์ปดํฌ๋ํธ๋ฅผ surveyId(1,2,3,4,5)๋ฅผ ๊ทธ๋ ค์ฃผ๋ฉด ๋๋ค.
return (
<section className="Recommend">
<h2 className="sr-only">recommend</h2>
<div className="surveyModal">
<div className="surveyBox">
<header className="surveyHeader">
<Link to="/">
<button className="closeButton">
<i class="fas fa-times" />
</button>
</Link>
<div className="villyLogo">Villy</div>
<h1>
๋น๋ฆฌ!
<br />
<strong>๋ด ๊ฑด๊ฐ์ ์๋ ค์ค!</strong>
</h1>
</header>
<div className="SurveyBox">{survey[this.state.surveyId]}</div>
</div>
</div>
</section>
);
Product ์ปดํฌ๋ํธ๋ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
๐ป ์ฝ๋ ํ์ค ํ์ค ๋ฏ์ด๋ณด๊ธฐ
โ๏ธ Product.js (๋ถ๋ชจ ์ปดํฌ๋ํธ) / import ๋ถ๋ถ
// ์ปดํฌ๋ํธ ์คํ ์ , import ํด์ฃผ์ด์ผ ํ๋ ๊ฒ๋ค์ ๋ํ ์ ๋ฆฌ !
//๋ฆฌ์กํธ์์ ์ปดํฌ๋ํธ ์์๋ฅผ import ํ ๋
import React, { Component } from 'react';
// API๋ config๋ผ๋ ํ์ผ๋ก ์ ์ฒด ๊ด๋ฆฌ
import { GET_PRODUCTS_API } from '../../config';
//์์ ์ปดํฌ๋ํธ ์์๋ฅผ import ํ ๋
import ProductCard from './ProductCard/ProductCard';
import ProductCategory from './ProductCategory/ProductCategory';
// ๊ณตํต์ผ๋ก ์ฌ์ฉ๋๋ ํจ์๋ฅผ ๋ถ๋ฆฌํ ๋ค import ํ ๋
import { makeCondition } from '../../utils/productUtils';
// scss๋ฅผ ๋ถ๋ฌ ์ฌ ๋
import './Product.scss';
์ฌ๊ธฐ์ ๊ฐ์ฅ ์ค์ํ import๋ผ๊ณ ์๊ฐํ๋ ๋ถ๋ถ์ config.js
์ makeCondition
์ import์ด๋ค.
1.config.js
๋จผ์ , config.js๋ API ์ฃผ์๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ํ์ผ์ด๋ค. config.js์ด ์กด์ฌํ๊ธฐ ์ ์๋ IP์ฃผ์๊ฐ ๋ฐ๋ ๋๋ง๋ค fetchํจ์๊ฐ ์ ์ฉ๋ ๋ชจ๋ ๊ณณ์์ ๋ฐ๊พธ์ด ์ฃผ์ด์ผ ํ๋๋ฐ ํ๋์ ํ์ผ๋ก ๊ด๋ฆฌํ๋, ๊ธฐ์ด๊ฐ ๋๋ IP์ฃผ์๋ง ๋ฐ๊ฟ ์ฃผ๋ฉด fetchํจ์๋ฅผ ์ผ์ผ์ด ๋ณ๊ฒฝํด์ค ํ์๊ฐ ์์ด์ ํจ์จ์ด ์ ๋ง ๋์์ก๋ค.
์๋๋ ๋ฉํ ๋์ ์์ธํ ์ค๋ช !
API๋ config.js ํ์ผ์์ ์ผ๊ด์ ์ผ๋ก ๊ด๋ฆฌํ๋ฉด์ import, export ๋ฅผ ํตํด ์ฌ์ฉํ๋ ์์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ, ๋ฐฑ์๋ ์๋ฒ IP ๊ฐ ๋ณ๊ฒฝ๋๋ฉด fetch ํจ์๋ฅผ ์ผ์ผ์ด ์ฐพ์์ API ๋ฅผ ์ง์ ์์ ํด ์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
config.js ์์ ๊ด๋ฆฌ๋ฅผ ํ๋ฉด์ import / export ๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ด ๊ตฌ์ฑ์ด ๋ ๊ฒ์ ๋๋ค.
2๏ธโฃ config.js
// src/config.js
const BASE_URL = 'http://10.58.5.151:8000'
export const GET_PRODUCT_API = `${BASE_URL}/products`
// ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ
import { GET_PRODUCT_API } from '../../../config.js';
...
fetch(`${GET_PRODUCT_API}/5`).then(...).then(...);
์์ ๊ฒฝ์ฐ, ๋ฐฑ์๋ IP ๊ฐ ๋ฐ๋ ๋ config.js ์์ IP ๋ง ๋ฐ๊พธ์ด์ฃผ๋ฉด ๋ชจ๋ API ๊ฐ ์๋ก์ด IP ์ ๋ฐ๋ผ์ ๋ณ๊ฒฝ๋ฉ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ผ์ผ์ด fetch ํจ์๋ฅผ ์ฐพ์ API ๋ฅผ ์์ ํด์ค ํ์๊ฐ ์์ต๋๋ค.
2. ProductUtils.js
makeCondition
์ ํจ์์ ๊ฒฝ์ฐ, ProductCategory์๋ ์ฌ์ฉ์ด ๋์ง๋ง, ์ดํ Recommend์ ๊ฒฐ๊ณผ ๊ฐ์๋ ์ฌ์ฉ๋๋ ๊ฒ์ ๋ฐ๊ฒฌํ์๋ค. ์ฝ๋์ ์ค๋ณต์ ํผํ๊ธฐ ์ํด์ ๋ฉํ ๋๊ป์ ํด๋น ํจ์๋ฅผ ๋ฃ์ด๋ ํ์ผ(ProductUtils.js
)์์ exportํ์ฌ ํ์ํ ๋๋ง๋ค importํ๋ ๋ฐฉ๋ฒ์ ๋ํ์ฌ ์๋ ค์ฃผ์
จ๋ค.
์ฌ์ง์ด ๋๋ ์กฐ๊ฑด์ ๋ง๋๋ ํจ์์์ ๋ฐ๋ก fetch๋ฅผ ํ๊ณ ์์๋๋ฐ ๋ฉํ ๋๊ป์ condition query๋ฅผ ๋ง๋๋ ๋ถ๋ถ๊ณผ fetch์์ฒญ ๋ฐ setState๋ฅผ ํ๋ ๊ธฐ๋ฅ์ด ๋ชจ๋ ํฌํจ๋์ด์๋ ํจ์๋ฅผ ๊ตฌํํ๋ ๊ฒ๋ณด๋ค fetch์์ฒญ ๋ฐ setState๋ฅผ ํ๋ ๋ถ๋ถ์ ๋ณ๋ ํจ์๋ก ๋ฐ๋ก ๋ถ๋ฆฌํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค๊ณ ํ์ จ๋ค.
์๋ํ๋ฉด ํจ์๋ฅผ ๊ธฐ๋ฅ๋ณ๋ก ๋๋๋ ์ด์ ๊ฐ ์ด๋ ๊ฒ ์์ ๊ธฐ๋ฅ๋ค๋ก ๋ค ๋๋๊ณ ๊ฐ์ ์กฐํฉํด์ ํ์ฉํ๊ธฐ ์ํจ์ด๊ธฐ ๋๋ฌธ์ด๋ค.
1๏ธโฃ Product.js (๊ธฐ์กด ์ฝ๋)
//๊ธฐ์กด์ฝ๋
makeCondition = () => {
const filterMatch = {
bone: 1,
hair: 2,
growth: 3,
skin: 4,
};
const filtered = Object.entries(this.state.filterState).reduce(
(acc, [key, value]) => {
if (!acc && value) {
return acc + `efficacy=${filterMatch[key]}`;
}
if (value) {
return acc + `&efficacy=${filterMatch[key]}`;
}
return acc;
},
''
);
return filtered;
};
handleCheckBox = event => {
const checkBoxName = event.target.name;
const checkBoxNameState = !this.state.filterState[checkBoxName];
this.setState(
{
filterState: {
...this.state.filterState,
[checkBoxName]: checkBoxNameState,
},
},
this.makeCondition
);
};
โฌ๏ธ ๊ธฐ์กด์ ์ด๋ ๊ฒ ๊ธด ํจ์๋ฅผ ์ปดํฌ๋ํธ์ ํจ๊ป ์์ฑํ์๋ค๋ฉด,
1๏ธโฃ Product.js (๋ฆฌํฉํ ๋ง ์ฝ๋)
// filtering์ ์ํ ํจ์
// query๋ผ๋ ๋ณ์์ makeCondition ํจ์(productUtils.js)์์ exprotํ return ๊ฐ์ ์ ์ฅํ์ฌ ๋ถ๋ฌ์จ๋ค.
fetchFiltering = () => {
const query = makeCondition(this.state.filterState);
fetch(`${GET_PRODUCTS_API}?${query}`)
.then(res => res.json())
.then(data => {
this.setState({
productCard: data.message,
});
});
};
// checkbox์ event๊ฐ ๋ฐ์ํ์ ๋, fetchFiltering ํจ์์ ๋ด๊ธด ๋ด์ฉ์ด ์งํ๋๊ฒ ํ๋ ํจ์
// ๊ฐ input์ name์ ์ด๋ฒคํธ์ state๊ฐ์ ํด๋ฆญํ์ ๋ ๋ฐ๊พธ์ด ์ค๋ค.
handleCheckBox = event => {
const checkBoxName = event.target.name;
const checkBoxNameState = !this.state.filterState[checkBoxName];
this.setState(
{
filterState: {
...this.state.filterState,
[checkBoxName]: checkBoxNameState,
},
},
this.fetchFiltering
);
};
โฌ๏ธ ์ข ๋ ๊ฐ๊ฒฐํ๊ฒ ํ์ํ ๊ฐ๋ง ๊ฐ์ง๊ณ ์ ์ฉํ ์ ์๋ค.
2๏ธโฃ productUtils.js
Product.js๋ก ์ ๋ฌํด์ค return ๊ฐ์ export ํด์ค๋ค!
//category-filter-condition
export const makeCondition = filterState => {
const filterMatch = {
bone: 1,
hair: 2,
growth: 3,
skin: 4,
};
const filtered = Object.entries(filterState).reduce((acc, [key, value]) => {
if (!acc && value) {
return acc + `efficacy=${filterMatch[key]}`;
}
if (value) {
return acc + `&efficacy=${filterMatch[key]}`;
}
return acc;
}, '');
return filtered;
};
์ค์ Recommend Feature์์ ์ฌ์ฉํ๋ ค๊ณ ๋ถ๋ฆฌํ์์ง๋ง,, ๋ง์ง๋ง์ ์๊ฐ์ด ๋ถ์กฑํ์ฌ Recommend์์๋ ์ ์ฅํ์ง ๋ชปํ๋ค. ๋ ๋ณํ์ง ์๋ ์์ ๊ฐ์ด๋ผ๋ฉด Ref๋ฅผ ํ์ฉํ์ฌ ์ ์ฉํ ์ ๋ ์๋ ๋ถ๋ถ์ด๋ผ๋ ์กฐ์ธ์ ๋ค์๋ค. ์ด๋ฏธ ๋ถ๋ฆฌ๋ ํ์ผ์ด๋๊น Recommend ํ์ด์ง์์ ์ ์ฉ๋ ์ ์๋๋ก ๋ฆฌํฉํ ๋งํด ๋ณผ ๊ฒ์ด๋ค!
โ๏ธ Product.js (๋ถ๋ชจ ์ปดํฌ๋ํธ) / changeProductCard ํจ์
Product.js์์ ๋ง๋ค์ด์ง ProductCard๋ค์ ๊ฐ๊ฐ์ ๋ฒํผ์ ๊ฐ์ง๊ณ ์๊ณ ํด๋น ๋ฒํผ์ ๋
๋ฆฝ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ฃผ์ด์ผ ํ๋ ์ํฉ์ด ๋ฐ์ํ์๋ค. ๋จธ๋ฆฌ๊ฐ ๋์ง ์์ ๋..ํด์ผํ ์ผ์ด ๋ฌด์์ธ์ง ์์ฐจ์ ์ผ๋ก ์ ์ด ์ ๊ทผํด๋ณธ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฌดํ ์ฝ์ ...!
- ์์์์์ state๋ฅผ ๋ถ๋ชจ์์ ๊ด๋ฆฌ ํด์ผํ๋ค.
์๋ํ๋ฉด, mapํจ์๋ฅผ ํตํด ๊ฐ ์ปดํฌ๋ํธ๋ก ์์ฑ๋ ์นด๋์ ๊ด๋ฆฌ๊ฐ ํ์ํ๋ค.- ProductCard ์ปดํฌ๋ํธ์์ ๋ช ๋ฒ์งธ ProductCard๊ฐ ํด๋ฆญ๋์๋์ง ์ ๋ณด ์ ๋ฌ์ด ํ์ํ๋ค.
- index ๊ฐ์ ์ ๋ฌํด์ฃผ์ด ํด๊ฒฐํ๋ค.
1๏ธโฃ Product.js
changeProductCard = (productCard, index) => {
const newProductCardList = [...this.state.productCard];
newProductCardList[index] = productCard;
this.setState({
productCard: newProductCardList,
});
};
์ด๋ป๊ฒ idnex๋ฅผ ๋๊ฒจ์ค์ ์๋์ง ๊ณ ๋ฏผํด๋.. ๋ต์ด ๋์ค์ง ์์๋ค. ๋ฐฉ๋ฒ์ ์์ง๋ง ์ ๊ทผํ์ง ๋ชปํ๋ ์ํฉ์ ๋ฉํ ๋๊ป์ newProductCardList[index]
๋ก ์ ๊ทผํ๋ฉด ๋๋ค๋ ๊ฒ์ ์๋ ค์ฃผ์
จ๋ค. ์์ง๋ {}, []
๋ฅผ ํ์ฉํ์ฌ ๋ด๊ฐ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด ์ฐ๋๊ฒ์ ์ต์ํ์ง ์๋ ๋๋ฅผ ๋ณด๋ฉฐ.. ์ฐธ ๋ง์ ์๊ฐ์ด ๋ค์๋ค. ๊ทธ๋ ๊ฒ ํด์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด๋ฉด !
ํด๋น index๋ฅผ ๊ฐ์ง productCard์ ๋ฐ์ดํฐ๋ง ์ถ์ถํด๋ผ ์ ์๋ค. changeProductCard
ํจ์๋ฅผ ์ด์ ์์์์์ธ productCard๋ก ์ ๋ฌํด์ฃผ๋ฉด ๊ฐ๊ฐ์ ๋
๋ฆฝ๋ productCard์ ๋ํ ์ํ๊ฐ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
1๏ธโฃ ProductCard.js
addCart = event => {
const { cart_exist } = this.props.productCard;
if (cart_exist) {
return;
}
event.preventDefault();
const newProductCard = { ...this.props.productCard };
newProductCard.cart_exist = true;
this.props.changeProductCard(newProductCard, this.props.index);
fetch(`${CARTLIST_API}`, {
method: 'POST',
headers: { Authorization: localStorage.getItem('access_token') },
body: JSON.stringify({
productID: event.target.name,
}),
});
};
์๋ก ์ ์๋ productCard์ state๊ฐ์ ๊ฐ๊ณตํ์ฌ ์ฅ๋ฐ๊ตฌ๋์ ๋ด๊น์ด๋ผ๋ ์๋ฏธ๋ฅผ ํํํ๋ 'cart_exist'๋ผ๋ ํค๊ฐ์ ๋ฐ๋ผ T/F์ ๋ฐ๋ฅธ ์กฐ๊ฑด์ ๋ถ์ฌํด์ฃผ๋ฉด ์ฅ๋ฐ๊ตฌ๋์ ๋ด๋ ๊ธฐ๋ฅ์ด ๊ฐ๋ฅํด์ง๋ค.
๋ํ ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์ ์ํ changeProductCard
ํจ์๋ productCard, index๋ฅผ ์ธ์๋ก ๋ฐ๊ธฐ ๋๋ฌธ์ ์ด ๋ถ๋ถ์ ํจ๊ป ์์ฑํด์ฃผ๋ฉด ๋๋ค.
Product Detail์ ์ฝ๋๋ ์ฌ๊ธฐ๋ก !