📃 image slider 코드에 대한 설명
import React, { useEffect, useState } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react'
import { Link } from 'react-router-dom'
import { Navigation, Pagination, Autoplay } from 'swiper/modules'
import { getBannerData } from '../api/bannerApi'
import css from './HeroSlider.module.css'
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
const HeroSlider = () => {
const [banner, setBanner] = useState([])
const [loading, setLoading] = useState(false)
useEffect(() => {
// 배너 데이터를 가져오기 전에 미리 첫 번째 이미지 프리로드
const preloadFirstImage = () => {
const img = new Image()
img.src = '/public/vite.svg' // 첫 번째 이미지 경로를 알고 있다면 직접 지정
}
preloadFirstImage()
const fetchBanner = async () => {
try {
setLoading(true)
const data = await getBannerData()
await delay(3000) // 1초 지연
setBanner(data)
setLoading(false)
} catch (err) {
console.log('err----', err)
setLoading(false)
}
}
fetchBanner()
}, [])
return (
<section>
<h2 hidden>Banner Event</h2>
<Swiper
pagination={{ clickable: true }}
modules={[Navigation, Pagination, Autoplay]}
className={css.mainSlider}
>
{loading ? (
<SwiperSlide>
<div className={`${css.skletion} ${css.imgWrap}`}></div>
</SwiperSlide>
) : (
banner.map(item => (
<SwiperSlide key={item.id}>
<div className={css.imgWrap}>
<img src={item.img} alt={item.title} />
</div>
<div className={css.textWrap}>
<p className={css.title}>{item.title}</p>
<p className={css.desc}>{item.description}</p>
<Link to={item.link} className={css.more}>
View Product
</Link>
</div>
</SwiperSlide>
))
)}
</Swiper>
</section>
)
}
export default HeroSlider
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
ms 밀리초 동안 기다렸다가 다음 코드 실행하는 유틸 함수이다.
유틸함수란?
짧고 단순한 도우미 함수
new Promise(...) | 비동기 처리를 가능하게 해준다. |
setTimeout(...,ms) | 일정 시간 후 콜백 실행 |
resolve() | Promise를 "성공 완료" 상태로 바꿈 |
Promise는 나중에 완료될 작업을 다룰 수 있게 해주는 객체이다.
...
/* 스켈레톤 ui */
.skletion::after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 1) 50%,
rgba(255, 255, 255, 0) 100%
);
/* animation: shimmer 2s; */
animation-name: shimmer;
animation-timing-function: ease-in;
animation-duration: 1s;
/* animation-fill-mode: both; */
/* animation-direction: alternate; */
animation-iteration-count: infinite;
transform: translateX(0%);
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
Positioin에 대한 설명
[URECA] Day 3 | CSS(2), 부트스트랩(1) — 오늘도 한줄
[URECA] Day 3 | CSS(2), 부트스트랩(1)
CSS Box ModelContent(내용) - 텍스트와 이미지가 나타나는 상자 내용Padding(패딩) - 콘텐츠 주변에 투명한 영역을 만들어 border과 content사이에 여백을 추가하는 역할border(경계, 테두리) - padding과 content를
recordoftheday.tistory.com
가상요소에 대한 설명
[CSS] ⭐ CSS Selectors(3) | Persudo Elements(가상 요소) — 오늘도 한줄
[CSS] ⭐ CSS Selectors(3) | Persudo Elements(가상 요소)
Persudo Elements(가상 요소) Pseudo element는 본질적으로 html에 존재하지 않는 요소이다. 그러나 CSS에서 여전히 선택하고 스타일을 지정할 수 있다. 의사 요소는 두 개의 콜론(::)을 사용하여 작성하면
recordoftheday.tistory.com
Animation에 대한 설명
[CSS] Animation
animation은 각 애니메이션 제어 속성의 단축 속성animation: 애니메이션이름 지속시간 대기시간? 타이밍함수? 반복횟수? 반복방향? 전후상태? 재생/정지?;값의미기본값animation-name@keyframes의 이름none an
recordoftheday.tistory.com
📃 LatestList 코드에 대한 설명
// Home화면에서 상품들이 나열되어 있는 걸 보여주는 페이지이다.
/**
useEffect: 컴포넌트가 렌더링될 때 특정 동작(부작용)을 실행하는 Hook
useEffect(실행하는 함수[, 의존하는 값])
→ 처음 한 번만 실행하고 싶으면 의존성 배열에 [] 빈 배열 입력
어떤 값이 변했을 때에 한해서만 어떤 처리를 실행하는 기능
===============================================================
useState: 상태값을 저장하는 Hook
const [state, setState] = useState(초기값)
첫번째 State변수, 두번째 그 State를 업데이트하기 위한 함수 설정
*/
// useEffect, useState 초기값 설정 방법
import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import css from './LatestList.module.css'
import ProductCard from '../components/ProductCard'
// 상품들의 목록을 가져와준다.
import { getProductsData } from '../api/productsApi'
const LatestList = () => {
// 상품 데이터를 저장할 state, Products를 업데이트 하기 위한 함수 설정
const [products, setProducts] = useState([])
useEffect(() => {
// 비동기 함수로 상품 목록을 API에서 가져와서 products 상태에 저장
const fetchProducts = async () => {
try {
const data = await getProductsData(`category=new&_limit=6`)
console.log('data----', data)
setProducts(data)
} catch (err) {
console.log('err----', err)
}
}
fetchProducts()
// [] -> 컴포넌트가 처음 마운트될 때 한 번만 실행, 의존성 값이 없다는 것(렌더링마다 실행되지 않음)
}, [])
return (
<section className={css.listCon}>
<h2>Shop The Latest</h2>
{/* 쇼핑으로 넘어가는 링크 */}
<Link to={'/shop'} className={css.more}>
View All
</Link>
<ul className={css.list}>
{/* map함수에서 배열을 순서대로 처리한 결과를 배열로 받는다.
products 배열을 순회하면서 각 상품 데이터를 ProductCard 컴포넌트로 렌더링한다.
각 항목은 <li>로 감싸고, React의 key로 data.id를 사용하여 고유 식별을 제공한다.*/}
{products.map(data => (
<li key={data.id}>
<ProductCard data={data} />
</li>
))}
</ul>
</section>
)
}
export default LatestList
<ul className={css.list}>
{products.map(data => (
<li key={data.id}>
<ProductCard data={data} />
</li>
))}
</ul>
map이란?
map함수에서 배열을 순서대로 처리한 결과를 배열로 받는다.
products 배열을 순회하면서 각 상품 데이터를 ProductCard 컴포넌트로 렌더링한다.
각 항목은 <li>로 감싸고, React의 key로 data.id를 사용하여 고유 식별을 제공한다.
🔍 스켈레톤 UI란?
콘텐츠가 로딩되는 동안 표시되는 저해상도 미리보기 또는 자리 표시자 화면으로, 실제 콘텐츠와 구조와 레이아웃을 시각적으로 나타낸다. 사용자에게 콘텐츠가 곧 표시될 것이라는 시각적 피드백을 제공하고, 페이지가 로딩 중이라는 인상을 주어 체감 로딩 시간을 줄여준다.
좋은 Progress Indicator란?
- 약 1초 이상 걸리는 작업에는 Progress Indicator를 사용하십시오.
- Loop Animation은 빠른 동작에만 사용하십시오.
- Percent-done Animation은 10초 이상 걸리는 작업에 사용하십시오.
- Static Indicator는 사용하지 마십시오.
무조건 스켈레톤 화면을 보여주는게 사용자 경험에 도움이 될까요? | 카카오페이 기술 블로그
무조건 스켈레톤 화면을 보여주는게 사용자 경험에 도움이 될까요? | 카카오페이 기술 블로그
카카오페이에서 프론트엔드 개발을 하며 스켈레톤 UI와 사용자 경험 향상에 대해 고민한 내용을 공유합니다.
tech.kakaopay.com
🐛 실습 중 겪은 문제
어제는 분명 로딩이 잘되었는데
오늘은 npm run dev를 하자마자 not found화면이 떴다.
그리 반갑지 않은 화면이다.
찾아보니 db.json이 있어서 json-server가 실행이 안되있어 나오는 문제이다.
다시 npm i 설치 후 npm run dev를 입력했는데도 화면에 렌더링이 안되었다.
⚙️ 해결과정
터미널에 직접 json-server 실행해 오류를 해결했다.
입력은
npx json-server db.json --port 3000
이렇게하면 json-server화면이 실행된다.