νλ‘μ νΈ ν€λ ΈνΈ πΌ
1. Nav animation
.line {
z-index: 1000;
width: 30px;
height: 3px;
margin: 7px 0px;
transition-duration: 0.5s;
background-color: #000;
}
.hamTopLine {
transform: translateY(10px) rotate(45deg);
transform-origin: center;
}
.hamMidLine {
opacity: 0;
}
.hamBtmLine {
transform: translateY(-10px) rotate(-45deg);
transform-origin: center;
}
}
ham
λ²νΌμ΄ λ¨μν μμΉν΄ μλ κ² μλλΌ μ μ μ μ‘μ
μ λ°μνμ¬ μμ§μ΄λλ‘ νκ³ μΆμλ€ !
3κ°μ λΌμΈ μ€ κ°μ΄λ° λΌμΈμ opacity
λ₯Ό μ£Όμ΄ μ보μ΄κ² μ²λ¦¬νκ³ μ΅μλ¨, μ΅νλ¨μ λΌμΈμ transform-origin: center
λ₯Ό μ£Όμ΄ κ°μ΄λ°λ₯Ό κΈ°μ μΌλ‘ μμ§μ΄κ² ν΄μ Xλ²νΌμ λ§λ€λλ‘ νλ€.
2. Nav @keyframes
animation: modalShowRight 0.3s;
@keyframes modalShowRight {
from {
opacity: 0;
margin-right: -50px;
}
to {
opacity: 1;
margin-right: 0;
}
}
animation
μμ±μ μ¬μ©νμ¬ modalShowRight
μ λλ©μ΄μ
μ μ§μμκ°μ 0.3μ΄λ‘ μ§μ ν΄ λΆλλ¬μ΄ μ λλ©μ΄μ
μ μ°μΆνκ³
keyframe
( from
κ³Ό to
)λ₯Ό μ¬μ©νμ¬ μ€λ₯Έμͺ½μμ μΌμͺ½μΌλ‘ λμ€λ ννμ μ λλ©μ΄μ
μ μ°μΆνλ€.
β
μ λλ©μ΄μ μμ΄ λͺ¨λ¬μ°½μ΄ κ·Έλ₯ λ΄μ λμ μ λλ©μ΄μ μ λΆμ¬ν΄μ λΆλλ½κ² λͺ¨λ¬μ°½μ΄ λ΄μ λ μμ±λ μ°¨μ΄κ° λ§μ΄ λ 보μλ€ ! κ΄λ ¨ cssλ₯Ό μ’ λ 곡λΆν΄λ΄μΌ ν κ² κ°λ€.
3. let token = localStorage.getItem('TOKEN')
localStorage
μ TOKEN
μ μ 무λ₯Ό νμΈνμ¬ useNavigate
hookμΌλ‘ κ²°κ³Όμ λ§λ νμ΄μ§λ‘ μ΄λνλ€.
4. config.js
export const BASE_URL = 'http://10.58.52.229:3000'
export const APIS = {
product: `${BASE_URL}/products`,
}
useEffect(() => {
fetch(`${APIS.product}/details/${productId}`)
.then(response => response.json())
.then(result => {
console.log(result)
setProductData(result.data)
})
}, [])
API
μ£Όμκ° μμ£Ό λ³κ²½λλ€ λ³΄λ κ·Έ λλ§λ€ κ° νμ΄μ§μ fetch
λ₯Ό μ°Ύμ μμ νλ €λ λ무 λ²κ±°λ‘μ λ€.
config.js
νμΌμ src
ν΄λ λ΄μ λ§λ€μ΄μ URL
μ μ€μ νκ³ κ° μλν¬μΈνΈλ§λ€ 미리 μμ±ν΄λμκ³ ,
μ΄ν λ³λμ΄ μκΈΈ μ config.js
νμΌ λ΄μ URL
λ§ μμ νλ©΄ λλλ‘ νλ€.
5. if (!productData?. productPrice ) return null
useEffect
λ΄λΆμ λ°μ΄ν°λ₯Ό λΆλ¬μ€κΈ° μ μ
UI
λ΄λΆμ map
μ΄λ reduce
κ°μ λ©μλλ₯Ό λ§λλ©΄ λ λλ§μ΄ μ€μ§λκ³ μλ¬λ©μΈμ§κ° λ΄λ€.
useEffect
λ‘ λ°μ΄ν° λΆλ¬μ€κΈ°κ° λ λλ§ λ€λ‘ λ°λ €λμ
μμ§ map
μ΄λ redudce
λ₯Ό μ€νν λ°°μ΄μ΄ λΆλ¬μμ§μ§ μμμμλλ°,
μ²μμλ
if (!productData) return null
λ§ μμ±νμλ€. κ·Έλ¬λλ μ΄λ€ λΆλΆμ ν΄κ²°μ΄ λκ³ ν΄κ²°μ΄ λμ§ μκ³ μλ¬λ©μΈμ§λ₯Ό λμ°λ μΌλΆκ° λ¨μλ€.
κ·Έλμ ?. (μ΅μ
λ 체μ΄λ μ°μ°μ)
λ₯Ό νμ©ν΄ productData
κ°μ²΄μ productPrice
νλ‘νΌν°μ
μ‘΄μ¬ μ¬λΆλ₯Ό νλ² λ 체ν¬νλλ‘ μ½λλ₯Ό μμ±ν΄μ ν΄κ²°νλ€.
?.
μ΅μ λ 체μ΄λ μ°μ°μ
?.
μμ νκ° λμμ΄undefined
λnull
μ΄λ©΄ νκ°λ₯Ό λ©μΆκ³undefined
λ₯Ό λ°ννλ€.
6. toLocaleString( )
product detail
νμ΄μ§μ purchase
νμ΄μ§μμ μν κ°κ²©μ΄λ μ΄κ³ λ±μ λͺ
μν λ
number type
μΌλ‘ κ³μ°μ νκ³ κ³μ°μ λ§μΉ λ€ toLocaleString()
λ‘ μ¬μ© μΈμ΄μ λ§λ ννμ ν¬ν¨ν΄μ£Όμλ€.
number
μ μ¬μ© μ 1,000 μ²λΌ νμν κ³³μ μΌνλ₯Ό μ°μ΄μ€λ€.
date
μ μ¬μ© μ λ¬ΈνκΆμ λ§λ μκ°νκΈ°λ²μΌλ‘ λ , μ, μΌ, μκ°μ 리ν΄ν΄μ€λ€.
array
μ μ¬μ©μarray
μ λ΄μ©μ λͺ¨λ λ¬Έμλ‘ λ°νν΄μ 보λ΄μ€λ€.
7. window.scrollTo(xμ’ν, yμ’ν)
onClick={() => {
const element = document.querySelector('.detailInformationBox')
if (element) {
const y = element.getBoundingClientRect().top - 100
window.scrollTo({ top: y, behavior: 'smooth' })
}
}}
μν μ 보λ 리뷰λ₯Ό ν΄λ¦νμ λ μνλ μμΉλ‘ μ€ν¬λ‘€μ΄ μ΄λνλλ‘ κ΅¬ννκ³ μΆμλ€ !
window. scrollTo()
λ‘λ§ μμ±νλ©΄ κ³ μ λ yκ°
μ μ§μ νκΈ° λλ¬Έμ
컨ν
μΈ μμ λ³λμ΄ μμ λ λ§λ€ μλ‘ μ§μ ν΄μ€μΌ νλ λ²κ±°λ‘μμ΄ μμλ€.
κ·Έλμ νΉμ μμμ κ°μ μ§μ νκΈ° μν΄ querySelector
λ‘ νΉμ ν΄λμ€μ ν΄λΉνλ μμλ₯Ό μ°Ύμ element
μ λ΄μ μ μΈνκ³
element.getBoundingClientRect().top
μ μ΄μ©ν΄ querySelector
λ‘ μ°Ύμ μμμ μλ¨ κ²½κ³κ°
λ·°ν¬νΈμ μλ¨κ³Ό μΌλ§λ λ¨μ΄μ§ κ²μΈμ§λ₯Ό μ§μ νλ€.
λ§μ§λ§μΌλ‘ window.scrollTo()
μ μμμ μ ν κ°μ top
μ μ§μ νκ³
behavior: 'smooth'
λ₯Ό ν΅ν΄ μ€ν¬λ‘€μ΄ λΆλλ½κ² μ΄λνλλ‘ νλ€.
8. img Carousel Box
<div className={`imgBox ${isCarousel ? '' : 'carousel'}`}>
<img
className="mainImg"
src={productData.mainThumbnailImage}
alt="productImage"
/>
<img
className="mainImg"
src={productData.mainThumbnailImage}
alt="productImage"
/>
</div>
//scss
.imgBox {
display: flex;
transform: translate(0px);
transition: 1s;
img {
width: 100%;
}
}
.carousel {
transform: translate(-500px);
}
.mainImg {
width: 500px;
flex: none;
object-fit: contain;
}
λ¨Όμ imgBox
div μμ carousel
κΈ°λ₯μΌλ‘ λμκ°κ² ν μ΄λ―Έμ§λ₯Ό 2κ° λμ΄νλ€.
mockdata
λ‘ μμ
ν λλ λ°°μ΄λ‘ κ΄λ¦¬ν΄μ index
λ‘ 2κ°μ μ΄λ―Έμ§λ₯Ό μμ
νμλλ°,
λ°±μλμ ν΅μ μ νκ² λλ©΄μ μμ λμλ€.
κΈ°λ³Έ imgBox
μ transform : translate(0px);
μ μ£Όμ΄ κΈ°λ³Έκ°μ μ£Όκ³ λ²νΌμ λλ μ λ
state
λ³κ²½μ λ°λ₯Έ carousel
μ΄λΌλ className
μ μΆκ°νμ¬ translate
λ₯Ό μλ‘ λΆμ¬ν΄ xμΆ
μΌλ‘ λ°μ΄μ£Όμλ€.
κΈ°λ³Έ class style
μ transition
μ μ£Όμ΄ λΆλλ½κ² μ΄λ―Έμ§κ° λμ΄κ° μ μλλ‘ νλ€.
μ¬μ€ μ²μμλ μ΄λ―Έμ§ λμ΄μ λ°°μ΄λ‘ κ΄λ¦¬ν΄λ³΄κ³ μΆμλλ°, λ€μμλ μ’ λ λ°°μ΄λ‘ κ΄λ¦¬νλ λ°©λ²μ μ°Ύμλ³΄κ³ μΆλ€.
9. TOKENμ λΆμ¬λ°μ νμμ λ°°μ‘μ§ μ 보 λ±λ‘(POST), input value κ΄λ¦¬
// purchase page
const [inputValue, setInputValue] = useState({
name: '',
phone: '',
address1: '',
address2: '',
memo: '',
// purchase λ΄ address component
const Address = ({
inputValue,
setInputValue,
}) => {
const { name, phone, address1, address2 } = inputValue
const handleUserInput = e => {
const { name, value } = e.target
setInputValue({ ...inputValue, [name]: value })
}
λ¨Όμ purchase
νμ΄μ§μ address
λͺ¨λ¬μμ λ°μ input valueλ₯Ό μΆλ ₯ν κ²μ΄κΈ° λλ¬Έμ
purchase
νμ΄μ§μ inputValue
μ setInputValue
stateλ₯Ό address
μμ λ°μμ μ¬μ©νλ€.
address
λ΄λΆμμλ inputValue
λ₯Ό λΉκ΅¬μ‘°ν ν λΉμ ν΅ν΄ name
, phone
, address1
, address2
λ‘ λΆν΄νκ³ μ΄λ₯Ό ν΅ν΄ κ°κ°μ κ°μ μ μ₯νκ³ μΆμ νλλ‘ νλ€.
λ§μ§λ§μΌλ‘ handleUserInput
ν¨μλ inputμ μ΄λ²€νΈλ₯Ό μ²λ¦¬νλ ν¨μμΈλ°,
e
λ₯Ό λ§€κ°λ³μλ‘ λ°μ e.target
μ name
κ³Ό value
λ₯Ό ꡬ쑰λΆν΄ν λΉμ μ΄μ©ν΄ μΆμΆνλ€.
κ·Έ ν μΆμΆν κ°μ λ€μ setInputValue
ν¨μλ₯Ό νΈμΆνμ¬ inputValue
μ μνλ₯Ό μ
λ°μ΄νΈνλλ°
μ΄ λ μ€νλ λ λ¬Έλ²(μ κ°μ°μ°μ) λ₯Ό μ¬μ©νμ¬ λ³΅μ¬ν [name]: value
λ₯Ό ν΅ν΄ ν΄λΉ μ
λ ₯ μμμ κ°μ μ
λ°μ΄νΈ νλλ‘ νλ€.
10. ꡬ쑰λΆν΄ ν λΉ λ° μ 체 λμ state κ΄λ¦¬
const [agreeList, setAgreeList] = useState({
isInfoAgree: false,
isUseAgree: false,
})
const { isInfoAgree, isUseAgree } = agreeList
const isAllChecked = Object.values(agreeList).every(list => list === true)
const handleAgree = name => {
setAgreeList(prev => ({ ...prev, [name]: !prev[name] }))
}
const handleAllCheck = () => {
if (isAllChecked) {
setAgreeList(prev => ({ ...prev, isInfoAgree: false, isUseAgree: false }))
} else {
setAgreeList(prev => ({ ...prev, isInfoAgree: true, isUseAgree: true }))
}
}
λμΌν μ½κ΄μ λν λμκ° μ’μΈ‘ νλ¨κ³Ό μ°μΈ‘ μλ¨ λλ²μ κ±Έμ³ μΆλ ₯λμ΄μλ€.
λ°λΌμ μ’μΈ‘μ λμμ μ°μΈ‘μ λμκ° μ°λλμ΄ κ΄λ¦¬λλλ‘ νλ©΄μ, κ²°κ³Όμ μΌλ‘ 4κ°μ λμκ° λͺ¨λ 체ν¬λμμ λ
μ 체 λμ 체ν¬λ°μ€μ 체ν¬κ° μλμΌλ‘ λ€μ΄μ€κ² νκ³ ,
μ 체 λμ 체ν¬λ°μ€λ₯Ό λλ₯΄λ©΄ λͺ¨λμ 체ν¬κ° λ€μ΄μ€κ±°λ λͺ¨λ μ¬λΌμ§κ² νκ³ μΆμλ€.
λ¨Όμ agreeList
stateλ₯Ό isInfoAgree
μ isUseAgree
λ‘ κ°μ²΄ ννλ‘ κ΅¬μ±νλ€.
κ·Έλ° λ€ agreeList
λ₯Ό isInfoAgree
μ isUseAgree
λ‘ κ΅¬μ‘°λΆν΄ ν λΉμ ν΄ μ¬μ©νκΈ° νΈνκ² λ§λ€μλ€.
isAllChecked
λ Object.values(agreeList)
λ₯Ό μ¬μ©νμ¬ κ°μ²΄κ°μ λ°°μ΄λ‘ λ³ννκ³
every
λ©μλλ₯Ό μ¬μ©νμ¬ list λ΄μ λͺ¨λ κ°μ μ£Όμ΄μ§ μ‘°κ±΄μΈ true
μ λΆν©νλ μ§ μ²΄ν¬νμ¬ μ μ₯νλλ‘ νλ€.
handleAgree
λ nameμ λ§€κ°λ³μλ‘ agreeList
κ°μ²΄ λ΄μ κ°κ°μ μμ±μ μΆμ νμ¬ μ²΄ν¬λ°μ€μ μνλ₯Ό κ°λ³μ μΌλ‘ κ΄λ¦¬νλ€.
λ§μ§λ§μΌλ‘ handleAllcheck
λ isAllchecked
μ λ°νκ°μ νμΈνμ¬
λ§μ½ true
μΈ μνλΌλ©΄ λͺ¨λ false
λ‘ λ³ννμ¬ λͺ¨λ 체ν¬λ°μ€λ₯Ό λλλ‘ νκ³
λ§μ½ false
μΈ μνλΌλ©΄ λͺ¨λ true
λ‘ λ³ννμ¬ λͺ¨λ 체ν¬λ°μ€λ₯Ό ν€λλ‘ νλ€.
Object.values()
: μ λ¬λ νλΌλ―Έν° κ°μ²΄κ° κ°μ§λ μμ±μ κ°λ§μΌλ‘ μ΄λ£¨μ΄μ§ λ°°μ΄μ 리ν΄νλ€..every
: λ°°μ΄ λ΄ λͺ¨λ μμκ° μ£Όμ΄μ§ νλ³μμ μΆ©μ‘±νλμ§ νμΈνμ¬boolean
κ°μ λ°ννλ€.
11. reduce λ©μλλ‘ μ΄ κΈμ‘ κ³μ° λ° κ΄λ¦¬
const totalPrice = orderList.reduce(
(acc, cur) => acc + cur.itemQuantity * cur.itemPrice,
0
)
orderList
λ ꡬ맀ν μνλ€μ κ°κ°μ κ°κ²©κ³Ό ꡬ맀 μλμ ν¬ν¨ν λ°°μ΄μ΄λ€.
reduce
λ΄μ acc
λ κΈ°μ‘΄ κ°, cur
μ νμ¬ κ°μ μλ―Ένλ€. reduce
λ λ°°μ΄μ λͺ¨λ μμλ₯Ό μννλ©°
μ ν΄μ§ ν¨μλ₯Ό μ€ννκ³ μ΄μ μ μ€νν΄μ λμΆν΄λμλ κ°, acc
μ ν©μ°νλ€. λͺ¨λ λ°°μ΄ μμμ μνμ΄ λλλ©΄ νλμ κ°μ λμΆν΄ λ°ννλ€.
reduce
: λ°°μ΄μ κ° μμμ λν΄ μ ν΄μ§ ν¨μλ₯Ό μ€ννκ³ νλμ κ²°κ³Όλ₯Ό λ°ννλ€.