reference:
useQuery
useQuery๋ React Query๋ฅผ ์ด์ฉํด ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ฌ ๋ ์ฌ์ฉํฉ๋๋ค.
โป ๋ฐ์ดํฐ ์กฐํ๊ฐ ์๋ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์
์ ํ ๋๋ ****์ ์ฌ์ฉํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ๋น์ ํ์๋ฉด select๋ฅผ ํ ๋ ์ฌ์ฉ
โข queryKey: queryKey์ ์ญํ ์ React-Query๊ฐ query ์บ์ฑ์ ๊ด๋ฆฌํ ์ ์๋๋ก ๋์์ค
โข queryFn
// 1
const res = useQuery(queryKey, queryFn);
// 2
const res = useQuery({
queryKey: queryKey,
queryFn: queryFn
});
option๊ฐ
// 1
const res = useQuery(['persons'], () => axios.get('<http://localhost:8080/persons>'), {
staleTime: 5000, // 5์ด
cacheTime: Infinity, // ์ ํ ์์
});
// 2
const res = useQuery({
queryKey: ['persons'],
queryFn: () => axios.get('<http://localhost:8080/persons>'),
staleTime: 5000, // 5์ด
cacheTime: Infinity // ์ ํ ์์
});
refetchOnWindowFocus ์ ์ญ์ค์
import * as React from 'react';
import ReactDom from 'react-dom';
import { QueryClient, QueryClientProvider } from 'react-query';
import App from './App';
const queryClient = new QueryClient(
{
defaultOptions: {
queries: {
refetchOnWindowFocus: false, // window focus ์ค์
}
}
}
); // queryClient ์์ฑ
ReactDom.render(
// App์ QueryClient ์ ๊ณต
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.querySelector('#root')
);
// 1
const res = useQuery(['persons'], () => axios.get('<http://localhost:8080/persons>'), {
refetchOnWindowFocus: false // window focus ์ค์
});
// 2
const res = useQuery({
queryKey: ['persons'],
queryFn: () => axios.get('<http://localhost:8080/persons>'),
refetchOnWindowFocus: false // window focus ์ค์
});
query ์๋์คํ ์ค์
ex)
if(id) {
const res = axios.get('<http://localhost:8080/person>', {
params: {
id: id,
}
})
}
useQuery์์๋ if๋ฌธ์ ์ฌ์ฉํ์ง ์๊ณ useQuery์์ ์ ๊ณตํด์ฃผ๋ query ์๋ ์คํ ์ค์ ์ ํตํด ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด ์ค ์ ์๋ค.
// 1
const res = useQuery(['person', id], () => axios.get('<http://localhost:8080/person>', {
params: {
id: id,
}
}), {
enabled: !!id // ์ฝ๋ ์๋ ์คํ ์ค์
});
// 2
const res1 = useQuery({
queryKey: ['person', id],
queryFn: () => axios.get('<http://localhost:8080/person>', {
params: {
id: id,
}
}),
enabled: !!id // ์ฝ๋ ์๋ ์คํ ์ค์
});
useMutation
useMutation์ React Query๋ฅผ ์ด์ฉํด ์๋ฒ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์
์ ์์ฒญํ ๋ ์ฌ์ฉํฉ๋๋ค.โป ๋ฐ์ดํฐ ์กฐํ๋ฅผ ํ ๋๋ useQuery๋ฅผ ์ฌ์ฉ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ๋น์ ํ์๋ฉด insert, update, delete๊ฐ ๋ชจ๋ ํฌํจ
์ฌ์ฉํํ
// 1
const savePerson = useMutation(mutationFn);
// 2
const savePerson = useMutation({
mutationFn: mutationFn
})
mutationFn์ mutation
Function์ผ๋ก promise
์ฒ๋ฆฌ๊ฐ ์ด๋ฃจ์ด์ง๋ ํจ์์
๋๋ค.
๋ค๋ฅธ ๋ง๋ก๋ axios
๋ฅผ ์ด์ฉํด ์๋ฒ์ API๋ฅผ ์์ฒญํ๋ ๋ถ๋ถ
// 1
const savePerson = useMutation((person: Iperson) => axios.post('/savePerson', person));
// 2
const savePerson = useMutation({
mutationFn: (person: Iperson) => axios.post('/savePerson', person)
})
mutate
mutate๋ useMutation
์ ์ด์ฉํด ์์ฑํ ๋ด์ฉ๋ค์ด ์คํ๋ ์ ์๋๋ก ๋์์ฃผ๋ trigger ์ญํ
์ฆ, useMutation
์ ์ ์ ํด๋ ๋ค ์ด๋ฒคํธ๊ฐ ๋ฐ์๋์์ ๋ mutate๋ฅผ ์ฌ์ฉ
const savePerson = useMutation((person: Iperson) => axios.post('<http://localhost:8080/savePerson>', person)); // useMutate ์ ์
const onSavePerson = () => {
savePerson.mutate(person); // ๋ฐ์ดํฐ ์ ์ฅ
}
<Person.SaveButton onClick={onSavePerson}>์ ์ฅ</Person.SaveButton>
onSuccess, onError, onSettled
์ผ๋ฐ์ ์ผ๋ก ์๋ฒ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์์ฒญ์ ํ๊ฒ ๋๋ฉด ๋ณ๊ฒฝ ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ์ ์ถ๊ฐ์ ์ธ ์ก์
์ ํ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ฑ.
์ด๋ฐ ์ํฉ์ useMutation์ ์ฌ์ฉํ ๋๋ ๋์ผํ๊ฒ ์ ์ฉ.
async/await
์ ์ฌ์ฉํ ๋๋ ๋ณดํต ๋ค์๊ณผ ๊ฐ์ด ๊ฒฐ๊ด๊ฐ์ด ์๋์ง๋ฅผ ํ์ธํ ๋ค ์ถ๊ฐ ์์
์ ์ํํ ์ ์๋ ์ฝ๋๋ฅผ ์์ฑ
try {
const res = await axios.post('<http://localhost:8080/savePerson>', person);
if(res) {
console.log('success');
}
} catch(error) {
console.log('error');
} finally {
console.log('finally');
}
useMutation
์ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ
// 1
const savePerson = useMutation((person: Iperson) => axios.post('<http://localhost:8080/savePerson>', person), {
onSuccess: () => { // ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
console.log('onSuccess');
},
onError: (error) => { // ์์ฒญ์ ์๋ฌ๊ฐ ๋ฐ์๋ ๊ฒฝ์ฐ
console.log('onError');
},
onSettled: () => { // ์์ฒญ์ด ์ฑ๊ณตํ๋ , ์๋ฌ๊ฐ ๋ฐ์๋๋ ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ
console.log('onSettled');
}
});
// 2
const savePerson = useMutation({
mutationFn: (person: Iperson) => axios.post('/savePerson', person),
onSuccess: () => { // ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
console.log('onSuccess');
},
onError: (error) => { // ์์ฒญ์ ์๋ฌ๊ฐ ๋ฐ์๋ ๊ฒฝ์ฐ
console.log('onError');
},
onSettled: () => { // ์์ฒญ์ด ์ฑ๊ณตํ๋ , ์๋ฌ๊ฐ ๋ฐ์๋๋ ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ
console.log('onSettled');
}
})
onSettled
๋ finally
๊ตฌ๋ฌธ์ฒ๋ผ ์์ฒญ์ด ์ฑ๊ณตํ๋ ์๋ฌ๊ฐ ๋ฐ์๋๋ ์๊ด์์ด ๋ง์ง๋ง์ ์คํ๋๋ ๊ตฌ๊ฐ
onSuccess, onError, onSettled
๋ useMutation
์ ์ ์ํ ๋๋ง ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด ์๋๋ผ mutate
์์๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
const onSavePerson = () => {
savePerson.mutate(person, {
onSuccess: () => { // ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
console.log('onSuccess');
},
onError: (error) => { // ์์ฒญ์ ์๋ฌ๊ฐ ๋ฐ์๋ ๊ฒฝ์ฐ
console.log('onError');
},
onSettled: () => { // ์์ฒญ์ด ์ฑ๊ณตํ๋ , ์๋ฌ๊ฐ ๋ฐ์๋๋ ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ
console.log('onSettled');
}
}); // ๋ฐ์ดํฐ ์ ์ฅ
}
invalidateQueries
useQuery
์์ ์ฌ์ฉ๋๋ queryKey
์ ์ ํจ์ฑ์ ์ ๊ฑฐํด์ฃผ๋ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ
queryKey
์ ์ ํจ์ฑ์ ์ ๊ฑฐํด์ฃผ๋ ์ด์ ๋ ์๋ฒ๋ก๋ถํฐ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ค๊ธฐ ์ํจ
์ ํด์ง ์๊ฐ์ด ๋๋ฌํ์ง ์์ผ๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๊ฐ ์ ์ฌ๋์๋๋ผ๋ useQuery
๋ ๋ณ๋ ์์ด ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ค ๊ฒ์
๋๋ค.
๊ฒฐ๊ตญ ์ฌ์ฉ์ ์
์ฅ์์๋ ๋ฐ์ดํฐ ์์ฑ์ด ์ ๋๋ก ๋์๋์ง์ ๋ํ ํ์
์ด ํ๋ค๊ธฐ ๋๋ฌธ์ ํผ๋์ ๊ฒช์ ์ ์๊ฒ ๋ฉ๋๋ค.
ํด๋น ์ํฉ์ ํด๊ฒฐํด์ค ์ ์๋ ๊ฒ์ด ๋ฐ๋ก invalidateQueries
์
๋๋ค.
๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ invalidateQueries
๋ฅผ ์ด์ฉํด useQuery
๊ฐ ๊ฐ์ง๊ณ ์๋ queryKey
์ ์ ํจ์ฑ์ ์ ๊ฑฐํด์ฃผ๋ฉด ์บ์ฑ๋์ด์๋ ๋ฐ์ดํฐ๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ฃผ์ง ์๊ณ ์๋ฒ์ ์๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ฒ ๋ฉ๋๋ค.
๊ฒฐ๊ตญ ๋ฐ์ดํฐ๊ฐ ์๋กญ๊ฒ ์ถ๊ฐ๋์์ ๋ ๋ค์ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๋ฉด์ ์ถ๊ฐํ ๋ฐ์ดํฐ๊น์ง ํ๋ฉด์์ ํ์ธํ ์ ์๊ฒ ๋ฉ๋๋ค.
const queryClient = useQueryClient(); // ๋ฑ๋ก๋ quieryClient ๊ฐ์ ธ์ค๊ธฐ
const savePerson = useMutation((person: Iperson) => axios.post('<http://localhost:8080/savePerson>', person), {
onSuccess: () => { // ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
console.log('onSuccess');
queryClient.invalidateQueries('persons'); // queryKey ์ ํจ์ฑ ์ ๊ฑฐ
},
onError: (error) => { // ์์ฒญ์ ์๋ฌ๊ฐ ๋ฐ์๋ ๊ฒฝ์ฐ
console.log('onError');
},
onSettled: () => { // ์์ฒญ์ด ์ฑ๊ณตํ๋ , ์๋ฌ๊ฐ ๋ฐ์๋๋ ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ
console.log('onSettled');
}
}); // useMutate ์ ์
setQueryData
invalidateQueries
๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธํด์ค ์ ์๋ ๋ฐฉ๋ฒ์ ์์ต๋๋ค.
setQueryData
๋ฅผ ํ์ฉํ๋ฉด ๋๋๋ฐ setQueryData
๋ ๊ธฐ์กด์ queryKey
์ ๋งคํ๋์ด ์๋ ๋ฐ์ดํฐ๋ฅผ ์๋กญ๊ฒ ์ ์ํด์ค๋๋ค.
const queryClient = useQueryClient(); // ๋ฑ๋ก๋ quieryClient ๊ฐ์ ธ์ค๊ธฐ
const savePerson = useMutation((person: Iperson) => axios.post('<http://localhost:8080/savePerson>', person), {
onSuccess: () => { // ์์ฒญ์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ
console.log('onSuccess');
queryClient.setQueryData('persons', (data) => {
const curPersons = data as AxiosResponse<any, any>; // persons์ ํ์ฌ ๋ฐ์ดํฐ ํ์ธ
curPersons.data.push(person); // ๋ฐ์ดํฐ push
return curPersons; // ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ก set
})
},
onError: (error) => { // ์์ฒญ์ ์๋ฌ๊ฐ ๋ฐ์๋ ๊ฒฝ์ฐ
console.log('onError');
},
onSettled: () => { // ์์ฒญ์ด ์ฑ๊ณตํ๋ , ์๋ฌ๊ฐ ๋ฐ์๋๋ ์คํํ๊ณ ์ถ์ ๊ฒฝ์ฐ
console.log('onSettled');
}
}); // useMutate ์ ์
useQueries
useQueries
๋ React Query์์ useQuery
์ ๋์ ๋ณ๋ ฌ ์ฟผ๋ฆฌ ์์
์ ์ํด ์ฌ์ฉ
useQueries
์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋จ์ํ๊ฒ useQuery
๋ฅผ ๋ฐฐ์ด๋ก ๋ฃ์ด์ค๋ค
const ress = useQueries([
useQuery1,
useQuery2,
useQuery3,
...
]);
const res1 = useQuery(['persons'], () => axios.get('<http://localhost:8080/persons>'), {
});
const res2 = useQuery(['person'], () => axios.get('<http://localhost:8080/person>', {
params: {
id: 1
}
}));
const res = useQueries([
{
queryKey: ['persons'],
queryFn: () => axios.get('<http://localhost:8080/persons>'),
},
{
queryKey: ['person'],
queryFn: () => axios.get('<http://localhost:8080/person>', {
params: {
id: 1
}
}),
}
]);
useQuery
๋ณด๋ค useQueries
๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ํฉ์ ๋์ ์ผ๋ก ๋ณํํ๋ ์ํฉ
const getPersons = (persons: Iperson[]) => {
const res = useQueries(
persons.map((person) => {
return {
queryKey: ['person', person.id],
queryFn: () =>
axios.get('<http://localhost:8080/person>', {
params: {
id: person.id,
},
}),
};
})
);
return (
<Person.Container>
{ress &&
ress.map((res) => {
const person: Iperson = res.data && res.data.data;
return (
person && (
<Person.Box key={person.id}>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
)
);
})}
</Person.Container>
);
};
Suspense
React Query์ suspense
๋ชจ๋๋ฅผ ์ค์ ํ๊ฒ ๋๋ฉด useQuery
์ status, error ๋ฑ์ React.Suspense
๋ก ๋์ฒด
// App.tsx
import * as React from 'react';
import Queries from './pages/queries';
const App = (): JSX.Element => {
return <Queries />;
};
export default App;
// queries.tsx
import axios from 'axios';
import * as React from 'react';
import { useQuery } from 'react-query';
import styled from 'styled-components';
interface Iperson {
id: number;
name: string;
phone: string;
age: number;
}
const Queries = (): JSX.Element => {
const getPersons = () => {
const res = useQuery(['persons'], () =>
axios.get('<http://localhost:8080/persons>')
);
// ๋ก๋ฉ ์ค์ผ ๊ฒฝ์ฐ
if (res.isLoading) {
return <LoadingText>Queries Loading...</LoadingText>;
}
// ๊ฒฐ๊ณผ๊ฐ์ด ์ ๋ฌ๋์์ ๊ฒฝ์ฐ
const persons: Iperson[] = res.data && res.data.data;
return (
<Person.Container>
{persons &&
persons.map((person) => {
return (
<Person.Box key={person.id}>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
);
})}
</Person.Container>
);
};
return <Wrapper>{getPersons()}</Wrapper>;
};
export default Queries;
// styled
const Wrapper = styled.div`
max-width: 728px;
margin: 0 auto;
`;
const LoadingText = styled.h3`
text-align: center;
`;
const Person = {
Container: styled.div`
padding: 8px;
`,
Box: styled.div`
border-bottom: 2px solid olive;
`,
Title: styled.h2`
display: inline-block;
margin: 0 12px;
line-height: 48px;
`,
Text: styled.span`
margin: 0 6px;
`,
};
React.Suspense
๋ฅผ ์ด์ฉํด ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ
์ฒซ ๋ฒ์งธ๋ App.tsx์ Queries Component๊ฐ React.Suspense๋ก ๋ฎ์ฌ์๋ค๋ ๊ฒ
๋ ๋ฒ์งธ๋ queries.tsx์ useQuery์ suspense ๋ชจ๋ ์ค์ ์ด ์ถ๊ฐ
์ธ ๋ฒ์งธ๋ queries.tsx์์ ๋ก๋ฉ ์ค์ผ ๊ฒฝ์ฐ์ ๋ํ ์ฝ๋๊ฐ ์ญ์
// App.tsx
import * as React from 'react';
import Queries from './pages/queries';
const App = (): JSX.Element => {
return (
<React.Suspense fallback={<div>App Loading...</div>}>
<Queries />
</React.Suspense>
);
};
export default App;
// queries.tsx
import axios from 'axios';
import * as React from 'react';
import { useQuery } from 'react-query';
import styled from 'styled-components';
interface Iperson {
id: number;
name: string;
phone: string;
age: number;
}
const Queries = (): JSX.Element => {
const getPersons = () => {
const res = useQuery(
['persons'],
() => axios.get('<http://localhost:8080/persons>'),
{
suspense: true, // suspense ๋ชจ๋ ์ค์
}
);
// ๊ฒฐ๊ณผ๊ฐ์ด ์ ๋ฌ๋์์ ๊ฒฝ์ฐ
const persons: Iperson[] = res.data && res.data.data;
return (
<Person.Container>
{persons &&
persons.map((person) => {
return (
<Person.Box key={person.id}>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
);
})}
</Person.Container>
);
};
return <Wrapper>{getPersons()}</Wrapper>;
};
export default Queries;
const Wrapper = styled.div`
max-width: 728px;
margin: 0 auto;
`;
const Person = {
Container: styled.div`
padding: 8px;
`,
Box: styled.div`
border-bottom: 2px solid olive;
`,
Title: styled.h2`
display: inline-block;
margin: 0 12px;
line-height: 48px;
`,
Text: styled.span`
margin: 0 6px;
`,
};
suspense
๋ชจ๋์์ useQueries
๋ฅผ ์ฌ์ฉ
suspense
๋ชจ๋์์ useQueries๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ ๋ useQuery๋ฅผ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ์ฌ ์ฌ์ฉํ๊ณ ์์ ๋ ๋ง์ฝ ํ๋์ useQuery๊ฐ ์ ์์ ์ผ๋ก ๋์๋์ง ์์ ๊ฒฝ์ฐ ๊ทธ ์ดํ์ ์คํ๋ useQuery์ ์ํฅ ์ ๋ฏธ์น๋ฉฐ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฌ๋ฐ๋ฅธ ํ๋ฉด์ด ๋ณด์ด์ง ์๊ธฐ ๋๋ฌธ
์ฒซ ๋ฒ์งธ ์์๋ ๊ฑธ๋ฌ์ง๊ณ ๋ ๋ฒ์งธ ์์์ ํด๋นํ๋ ๊ฒฐ๊ณผ๋ง ํ๋ฉด์ ๋
ธ์ถ
import axios from 'axios';
import * as React from 'react';
import { useQueries } from 'react-query';
import styled from 'styled-components';
interface Iperson {
id: number;
name: string;
phone: string;
age: number;
}
const Queries = (): JSX.Element => {
const getPersons = () => {
const res = useQueries([
{
queryKey: ['persons'],
queryFn: () => axios.get('<http://localhost:8080/personssss>'), // ์ค๋ฅ
suspense: true,
},
{
queryKey: ['person'],
queryFn: () =>
axios.get('<http://localhost:8080/person>', {
params: {
id: 1,
},
}),
suspense: true,
},
]);
if (res) {
const persons: Iperson[] = res[0].data && res[0].data.data;
const person: Iperson = res[1].data && res[1].data.data;
return (
<Person.Container>
{persons && persons.map((person) => {
return (
<Person.Box key={person.id}>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
);
})}
{person && (
<Person.Box>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
)}
)}
</Person.Container>
);
}
};
return <Wrapper>{getPersons()}</Wrapper>;
};
export default Queries;
const Wrapper = styled.div`
max-width: 728px;
margin: 0 auto;
`;
const Person = {
Container: styled.div`
padding: 8px;
`,
Box: styled.div`
border-bottom: 2px solid olive;
`,
Title: styled.h2`
display: inline-block;
margin: 0 12px;
line-height: 48px;
`,
Text: styled.span`
margin: 0 6px;
`,
};
useInfiniteQuery
useInfiniteQuery
๋ ํ๋ผ๋ฏธํฐ ๊ฐ๋ง ๋ณ๊ฒฝํ์ฌ ๋์ผํ useQuery
๋ฅผ ๋ฌดํ์ ํธ์ถํ ๋ ์ฌ์ฉ
const res = useInfiniteQuery(queryKey, queryFn);
pageParam
์ useInfiniteQuery
๊ฐ ํ์ฌ ์ด๋ค ํ์ด์ง์ ์๋์ง๋ฅผ ํ์ธํ ์ ์๋ ํ๋ผ๋ฏธํฐ ๊ฐ
const res = useInfiniteQuery(['infinitePerson'], ({ pageParam = 5 }) =>
axios.get('<http://localhost:8080/person>', {
params: {
id: pageParam,
},
})
);
๊ธฐ๋ณธ ๊ฐ์ undefined
์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ด ์์ ๊ฒฝ์ฐ ์ด๊ธฐ๊ฐ์ผ๋ก 5 ์ค์
๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ฌ ๋ pageParam
๊ฐ์ api ์์ฒญํ ๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ผ๋ก ๋ฃ์ด ์ฌ์ฉ
getNextPageParam๊ณผ fetchNextPage
getNextPageParam
๊ณผ fetchNextPage
์ ๊ณตํต์ ์ผ๋ก ๋ค์ ํ์ด์ง์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ฌ ๋ ์ฌ์ฉ
getNextPageParam์ ๋ค์ api๋ฅผ ์์ฒญํ ๋ ์ฌ์ฉ๋ pageParam๊ฐ์ ์ ํ ์ ์๋ค
const res = useInfiniteQuery(
['infinitePerson'],
({ pageParam = 5 }) =>
axios.get('<http://localhost:8080/person>', {
params: {
id: pageParam,
},
}),
{
getNextPageParam: (lastPage, allPages) => {
return lastPage.data.id + 1; // ๋ค์ ํ์ด์ง๋ฅผ ํธ์ถํ ๋ ์ฌ์ฉ ๋ pageParam
},
}
);
lastPage
๋ useInfiniteQuery
๋ฅผ ์ด์ฉํด ํธ์ถ๋ ๊ฐ์ฅ ๋ง์ง๋ง์ ์๋ ํ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์๋ฏธํฉ๋๋ค.
allPages
๋ useInfiniteQuery
๋ฅผ ์ด์ฉํด ํธ์ถ๋ ๋ชจ๋ ํ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์๋ฏธ
return
๋๋ ๊ฐ์ด ๋ค์ ํ์ด์ง๊ฐ ํธ์ถ๋ ๋ pageParam
๊ฐ
fetchNextPage๋ ๋ค์ ํ์ด์ง์ ๋ฐ์ดํฐ๋ฅผ ํธ์ถํ ๋ ์ฌ์ฉ
useInfiniteQuery์ return ๊ฐ์ ํฌํจ๋๋ฉฐ ๋ค์๊ณผ ๊ฐ์ด ๋ฒํผ์ ํด๋ฆญํ ๋ ์คํ๋ ์ด๋ฒคํธ๋ก ๋ฑ๋กํด์ค ์ ์๋ค
const getPersons = () => {
const res = useInfiniteQuery(
['infinitePerson'],
({ pageParam = 5 }) =>
axios.get('<http://localhost:8080/person>', {
params: {
id: pageParam,
},
}),
{
getNextPageParam: (lastPage, allPages) => {
return lastPage.data.id + 1; // ๋ค์ ํ์ด์ง๋ฅผ ํธ์ถํ ๋ ์ฌ์ฉ ๋ pageParam
},
}
);
// ๋ก๋ฉ ์ค์ผ ๊ฒฝ์ฐ
if (res.isLoading) {
return <LoadingText>Loading...</LoadingText>;
}
// ๊ฒฐ๊ณผ๊ฐ์ด ์ ๋ฌ๋์์ ๊ฒฝ์ฐ
if (res.data) {
return (
<Person.Container>
{res.data.pages.map((page) => {
const person: Iperson = page.data;
return (
<Person.Box key={person.id}>
<Person.Title>{person.id}.</Person.Title>
<Person.Text>{person.name}</Person.Text>
<Person.Text>({person.age})</Person.Text>
</Person.Box>
);
})}
<Person.NextButton onClick={() => res.fetchNextPage()}>
Next
</Person.NextButton>{' '}
{/* ํด๋ฆญ ์ ๋ค์ ํ์ด์ง ํธ์ถ */}
</Person.Container>
);
}
};
import axios from 'axios';
import * as React from 'react';
import { useEffect, useRef, useState } from 'react';
// info interface
interface Info {
name: string;
phone: string;
age: number;
}
const App = (): JSX.Element => {
// state
const [infoArray, setInfoArray] = useState<Info[]>([]);
// ref
const observerRef = useRef<IntersectionObserver>();
const boxRef = useRef<HTMLDivElement>(null);
// useEffect
useEffect(() => {
getInfo();
}, []);
useEffect(() => {
observerRef.current = new IntersectionObserver(intersectionObserver); // IntersectionObserver
boxRef.current && observerRef.current.observe(boxRef.current);
}, [infoArray]);
// function
const getInfo = async () => {
const res = await axios.get('<http://localhost:8080/rest/getInfo>'); // ์๋ฒ์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
setInfoArray((curInfoArray) => [...curInfoArray, ...res.data]); // state์ ์ถ๊ฐ
// console.log('info data add...');
};
// IntersectionObserver ์ค์
const intersectionObserver = (
entries: IntersectionObserverEntry[],
io: IntersectionObserver
) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// ๊ด์ฐฐํ๊ณ ์๋ entry๊ฐ ํ๋ฉด์ ๋ณด์ฌ์ง๋ ๊ฒฝ์ฐ
io.unobserve(entry.target); // entry ๊ด์ฐฐ ํด์
getInfo(); // ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
}
});
};
// style
const Wrapper = {
width: '800px',
margin: '0 auto',
};
const Box = {
border: '1px solid olive',
borderRadius: '8px',
boxShadow: '1px 1px 2px olive',
margin: '18px 0',
};
const BoxTable = {
borderSpacing: '15px',
};
const Title = {
fontWeight: 700,
};
return (
<div style={Wrapper}>
{infoArray.map((info, index) => {
if (infoArray.length - 5 === index) {
// ๊ด์ฐฐ๋๋ ์์๊ฐ ์๋ html, ์๋์์ 5๋ฒ์งธ์ ํด๋นํ๋ ๋ฐ์ค๋ฅผ ๊ด์ฐฐ
return (
<div style={Box} ref={boxRef} key={index}>
<table style={BoxTable}>
<tbody>
<tr>
<td style={Title}>์ด๋ฆ</td>
<td>{info.name}</td>
</tr>
<tr>
<td style={Title}>์ ํ๋ฒํธ</td>
<td>{info.phone}</td>
</tr>
<tr>
<td style={Title}>๋์ด</td>
<td>{info.age}</td>
</tr>
</tbody>
</table>
</div>
);
}
// ๊ด์ฐฐ๋๋ ์์๊ฐ ์๋ html
return (
<div style={Box} key={index}>
<table style={BoxTable} key={index}>
<tbody>
<tr>
<td style={Title}>์ด๋ฆ</td>
<td>{info.name}</td>
</tr>
<tr>
<td style={Title}>์ ํ๋ฒํธ</td>
<td>{info.phone}</td>
</tr>
<tr>
<td style={Title}>๋์ด</td>
<td>{info.age}</td>
</tr>
</tbody>
</table>
</div>
);
})}
</div>
);
};
export default App;