ํฌ์ผ๋ชฌ API๋ฅผ ํ์ฉํด ํฌ์ผ๋ชฌ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ณ ์์๋ค.
๋ฌดํ ์คํฌ๋กค ๊ตฌํ์ ์ํด ๋ทฐํฌํธ ๋ฐ๋ฅ์ ๋ฟ์ ๊ฒฝ์ฐ ํฌ์ผ๋ชฌ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐ๋ก Get์์ฒญ์ ๋ณด๋ด๋๋ก ํ๋ค.
const PokeContList = () => {
const [offset, setOffset] = useState<number>(0);
const [pokemonList, setPokemonList] = useState<PokeList[]>([]);
const LIMIT = 20;
useQuery({
queryKey: ['pokeList'],
queryFn: () => upDatePokemon(),
onSuccess(data) {
setPokemonList(data);
},
onError(err) {
console.log(err);
},
});
const upDatePokemon = async () => {
const getPokemonListData = await getPokemonList(LIMIT, offset);
const nextPokeMonList = getPokemonListData.results;
setOffset((prevOffset) => (prevOffset = prevOffset + LIMIT));
setPokemonList((prevList) => [...prevList, ...nextPokeMonList]);
return nextPokeMonList;
};
const eventScroll = () => {
const { scrollHeight, scrollTop, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight) {
console.log('๋ฐ๋ฅ');
upDatePokemon();
}
};
useEffect(() => {
window.addEventListener('scroll', eventScroll);
console.log('๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ');
return () => {
window.removeEventListener('scroll', eventScroll);
};
}, [pokemonList]);
console.log('์นด๋ ์ปดํฌ๋ํธ๋ฆฌ์คํธ');
return (
<PokeContainer>
{pokemonList && pokemonList.map((pokemon) => <PokeInfoCard key={pokemon.name} name={pokemon.name} />)}
</PokeContainer>
);
};
export default PokeContList;
๋ณด๋๊ฑฐ์ ๊ฐ์ด ์ฝ์์ฐฝ์ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ๊ฐ ์ฌ๋ฌ๋ฒ ์ฐํ๋๊ฑธ ๋ณผ ์ ์๋ค.
useEffect๋ ํ์ฌ ์์กด์ฑ ๋ฐฐ์ด๋ก pokemonList๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
๋ฐ๋ผ์, ์ฒ์ ๋ ๋๋ง ๋ ์ดํ pokemonList์ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด useEffect๊ฐ ์คํ๋๋ค.
์ด๊ธฐ ํ๋ฉด ์ง์
์ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ก ๋ถ๋ฌ์ ์ง์ง ์์ผ๋
๋ทฐํฌํธ ๋ฐ๋ฅ์ด ๋ฐ๋ก ๋
ธ์ถ ๋๋ฉด์ eventScroll ํจ์๊ฐ ์คํ๋์ด ๋ถํ์ํ ๋ฐ์ดํฐ๊ฐ ํธ์ถ ์ด์๊ฐ ๋ฐ์ํ๋ค ์๊ฐํ๋ค.
์ด๋ฐ์๋ useEffect์ ์กฐ๊ฑด์ ๊ฑธ์ด ๋ดค์ง๋ง
์กฐ๊ฑด์ด ์ถฉ์กฑ๋์ง ์์ ๋ฌดํ ์คํฌ๋กค์ด ์คํ๋์ง ์์๋ค.
์ด๋ป๊ฒ ํด๊ฒฐํ์ง? ๋ผ๋ ์๊ฐ์ผ๋ก ํ์ฐธ ๊ณ ๋ฏผํ๋ ์ค ์ค์ผ๋ ํค
์ ์๊ฐํ๊ฒ ๋์๋ค.
์ค์ผ๋ ํค=๋ผ๋
ํ์ด์ง ์ฝํ ์ธ ๊ฐ ์์ ํ ๋ ๋๋ง๋๊ธฐ ์ ์ ๋ํ๋๋ ํ๋ฉด, ์ต์ข ์ฝํ ์ธ ๊ฐ ์ ์๋ฆฌ์ ๋ก๋๋๊ธฐ ์ ์ ํ์ด์ง ๊ตฌ์กฐ์ ์ค๊ณฝ์ ๋ํ๋ด๋ ์ฐํ ์์์ ๋ฐฐ๊ฒฝ, ์ ๋ฐ ํ ์คํธ๋ก ๊ตฌ์ฑ
[React] ์ค์ผ๋ ํค ๋ก๋ฉ์ด๋? - by07a๋
๋งํ์๋ฉด ๋ด๊ฐ ๋ณด์ฌ์ฃผ๋ ค๊ณ ํ๋ ์ปจํ ์ธ ์ ๋์ผํ ์ฌ์ด์ฆ๋ก ๋ง๋ค์ด์ง ํ์ ์ปจํฌ๋ํธ๋ฅผ ๋ฐ์ดํฐ๊ฐ ๋ก๋ฉ ๋ ๋ ๊น์ง ํ๋ฉด์ ํ์ํ๋ ๊ฒ์ ๋งํ๋ค.
import styled, { keyframes } from 'styled-components';
const load = keyframes`
100% {
background-position: -100% 0;
}
`;
const SkeletonWrap = styled.div`
position: relative;
overflow: hidden;
border-radius: 10px;
background: linear-gradient(90deg, #e5e5e5 30%, #f0f0f0 30%, #f0f0f0 30%, #e5e5e5 50%);
background-size: 200% 100%;
background-position: 100% 0;
animation: ${load} 1.5s infinite;
/* box-shadow: 4px 4px 20px 0 rgba(0, 0, 0, 0.1); */
padding: 20px;
display: flex;
flex-direction: column;
align-items: flex-end;
z-index: 1;
cursor: pointer;
transition: 0.3s;
width: 100%;
height: 0;
padding-bottom: 100%;
background-color: #ccc;
`;
const SkeletonCard = () => {
return (
<>
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
<SkeletonWrap />
</>
);
};
export default SkeletonCard;
์ ์ ๊ฐฏ์๋ก ๊ตฌ์ฑํ๋ ค๊ณ ํ์ง๋ง
๋ทฐํฌํธ ๋ฐ๋ฅ์ด ๊ณ์ ๋ฟ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํด 12๊ฐ์ ์นด๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ๋ฐฐ์นํ๋ค.
์ ๋๋ฉ์ด์ ํจ๊ณผ๋ ๊ตฌ๊ธ๋ง์ ํตํด ๊ฐ์ ธ์ ์์ ๋ฐฐ์น๋ฅผ ์ปค์คํฐ๋ง์ด์งํด ์์ ํ๋ค.
๊ทธ๋ฌ๊ณ ๋ค์ ์ฝ์์ฐฝ์ ํ์ธํด ๋ดค๋๋ฐ ๋์ผํ๊ฒ ๋์๋ค...
๋ทฐํฌํธ๊ฐ ๋ฐ๋ฅ์ ๋ฟ๊ธฐ ์ ์ ์ค์ผ๋ ํค์ ๋ณด์ด๊ฒ ํ์ง๋ง ๊ทธ ๋ฌธ์ ๊ฐ ์๋์๋ ๊ฒ ๊ฐ์
useEffect ์ฝ๋๋ฅผ ๋ค์ ํ์ธํด ๋ณด์.
const [offset, setOffset] = useState<number>(0);
const [pokemonList, setPokemonList] = useState<PokeList[]>([]);
const LIMIT = 20;
useQuery({
queryKey: ['pokeList'],
queryFn: () => upDatePokemon(),
onSuccess(data) {
setPokemonList(data);
console.log('useQuery ์คํ');
},
onError(err) {
console.log(err);
},
});
const upDatePokemon = async () => {
const getPokemonListData = await getPokemonList(LIMIT, offset);
const nextPokeMonList = getPokemonListData.results;
setOffset((prevOffset) => (prevOffset = prevOffset + LIMIT));
setPokemonList((prevList) => [...prevList, ...nextPokeMonList]);
console.log('upDatePokemon ์คํ');
return nextPokeMonList;
};
const eventScroll = () => {
const { scrollHeight, scrollTop, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight) {
console.log('๋ฐ๋ฅ๊ฐ์ง ์
๋ฐ์ดํธ');
upDatePokemon();
}
};
useEffect(() => {
window.addEventListener('scroll', eventScroll);
console.log('๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ');
return () => {
window.removeEventListener('scroll', eventScroll);
};
}, [pokemonList]);
console.log('์นด๋ ์ปดํฌ๋ํธ๋ฆฌ์คํธ', pokemonList);
๊ฐ๊ฐ์ ๊ตฌ๊ฐ์ console.log
๋ฅผ ์ถ๊ฐํด ํ์ธํ๊ธฐ๋ก ํ๋ค.
๐ ๋ฌธ์ ์ ๋ฐ๊ฒฌ!
useEffect์ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐ๋์ด ์๋ pokemonList์ ์ํ๊ฐ ๋ณ๊ฒฝํ๋ฉด useEffect ๋ด๋ถ์ ์ฝ๋๊ฐ ์คํ๋๋ค.
์ฒ์์๋ pokemonList๊ฐ ๋น๋ฐฐ์ด๋ก ์์ ๋๋๋ฐ ์ฌ๊ธฐ์ useEffect๊ฐ ๋๋ฒ ์คํํ๋ ๊ฒ ๊ฐ๋ค.
useQuery๋ฅผ ํตํด upDatePokemon()
์ด ์คํ๋๊ณ pokemoList์ ๋ฐ์ดํฐ๊ฐ ๋ค์ด์ค๊ฒ ๋๋ค.
์ฌ๊ธฐ์ ์ธ๋ฒ์งธ useEffect๊ฐ ์คํ ๋๋ ๊ฒ ๊ฐ์๋ค.
useEffect(() => {
if (pokemonList.length > 0) {
window.addEventListener('scroll', eventScroll);
console.log('๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ');
return () => {
window.removeEventListener('scroll', eventScroll);
};
}
}, [pokemonList]);
์ง๊ด์ ์ผ๋ก ํ์ํ ์ ์๊ฒ pokemonList
๋ฐฐ์ด์ ๊ธธ์ด๊ฐ 0๋ณด๋ค ํด ๊ฒฝ์ฐ useEffect ๋ด๋ถ ์ฝ๋๊ฐ ์คํํ๊ฒ ์กฐ๊ฑด๋ฌธ์ ์ถ๊ฐํ๋ค.
๋ค์ ์ฝ์์ฐฝ์ ํ์ธํ๋ useEffect๊ฐ ๋ถํ์ํ๊ฒ ๋๋ฒ ์คํ๋๋ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋ ๊ฑธ ๋ณผ ์ ์์๋ค...!
useEffect(() => {
const eventScroll = () => {
const { scrollHeight, scrollTop, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight) {
console.log('๋ฐ๋ฅ๊ฐ์ง ์
๋ฐ์ดํธ');
upDatePokemon();
}
console.log('๋ฐ๋ฅ๊ฐ์ง ์คํ');
};
if (pokemonList.length > 0) {
window.addEventListener('scroll', eventScroll);
console.log('๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ');
return () => {
window.removeEventListener('scroll', eventScroll);
};
}
}, [pokemonList]);
๊ทธ๋ฆฌ๊ณ eventScroll๋ pokenomList์ ๋ฐฐ์ด ๊ธธ์ด๊ฐ 0์ด์์ธ ๊ฒฝ์ฐ, ์คํฌ๋กค์ด ๋ฐ๋ฅ์ ๋ฟ์ ๊ฒฝ์ฐ์๋ง ์คํ๋๊ธฐ์ useEffect ๋ด๋ถ์ ๊ฐ์ด ๋ฌถ์ด ์ฃผ์๋ค.
์ด๋ฒ ์๊ฐ์ ํตํด console.log๋ฅผ ์ ํ์ฉํด ๋ฌธ์ ๋ฅผ ํ์
ํ์๋ ์ ,
useEffect๋ฅผ ์ฌ์ฉํ ๋๋ ๋ถํ์ํ ๋ ๋๋ง์ ๋ง๊ธฐ ์ํด ์กฐ๊ฑด๋ฌธ์ด๋ ์์กด์ฑ ๋ฐฐ์ด์ ์ถ๊ฐํด ์ฃผ๋ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ๋ฉด์ ์ฌ์ฉํด์ผ ๊ฒ ๋ค๋ ๊ตํ์ ์ป์ ์ ์์๋ค.