React Query 알아보기

ms_de10·2024년 8월 19일
0

‘React Query’는 React에서 서버 상태를 효율적으로 관리하기 위한 라이브러리입니다. 서버 데이터의 패칭, 캐싱, 동기화, 업데이트를 쉽게 처리할 수 있게 해주며, 복잡한 상태 관리 로직을 간소화합니다.

언제 React Query를 사용해야 할까?

React Query는 주로 서버 상태를 관리할 때 사용합니다. 서버 상태란 API를 통해 가져오는 데이터로, 애플리케이션 외부에 존재하며 지속적인 동기화가 필요한 데이터를 말합니다. 

서버 데이터와 로컬 상태를 명확히 구분하여 관리할 수 있어 상태 관리의 복잡성을 줄일 수 있습니다. 여러 컴포넌트에서 동일한 데이터를 사용할 때도 React Query가 자동으로 데이터를 동기화하여 일관성을 유지합니다.

React Query 기본 개념의 이해

리액트 쿼리는 세가지 핵심 개념을 가지고 있는데 Query 와 Mutation, QueryClient와 QueryClientProvider, useQuery와 useMutaion 훅 으로 이루어지며 데이터 패칭과 상태관리를 간소화 할 수 있다.

Query와 Mutation

query는 데이터를 읽어오는 작업, Mutation은 데이터를 변경하는 작업을 의미한다.

//Query 작업

const {data, isLoading, error} = useQuery('todos', fetchTodos);
// istLoading이 true일 때 : data는 undefined, error는 null
// 데이터 로드 성공 시 : data는 fetched data, isLodaing은 false, error는 null
// 에러 발생 시: data는 undefined, isLoading은 false, error는 Error 객체
const mutation = useMutation((newTodo)=>{
	return axios.post('/todos', newTodo)
})

mutation.mutate((title: 'New Todo'))
// mutation.isLoading: true during the mutation
// mutation.isError: true if an error occurrd
// mutation.isSuccess: true if the mutation succeeded

QueryClient와 QueryClientProvider

이 두 요소는 React Query의 설정과 컨텍스트를 제공하여 앱 전체에서 일관된 방식으로 사용 가능

const queryClient = new QueryClient();

function App() {
	return (
		<QueryClientProvider client={queryClient}>
		{애플리케이션 컴포넌트들}
		</QueryClientProvider>
	)
}
// 이 설정으로 모든 하위 컴포넌트에서 React Query 기능을 사용할 수 있다.

useQuery와 useMutation 훅

이 훅들은 실제로 데이터를 가져오고 변경하는 데 사용됨

const {data, isLoading, error} = useQuery('todos', fetchTodos)

const mutation = useMutation((newTodo)=> {
	return axios.post('/todos', newTodo)
})

사용 예시

useQuery 사용 예시

const [checked, setChecked] = useState(false)
const {istLoading, error, data: products} = useQuery({
	queryKey: ['products', checked],
	queryFn: async()=>{
	console.log('fetching...', checked)
	const reponse = await fetch(`data/${checkd ? 'item_' : ''}products.json`)
	return await response.json()
	}
	staleTime: 1000*60*3
})

if( isLoading) return <p> loading...</p>
if (error) return <p> {error} </p>

useMutation 사용예시 - 서버의 데이터 변경 추가나 삭제

const addTodo = (newTodo)=> fetch(`https://jsonplaceholder.typicode.com/todos`,{
	method:'POST',
	headers: {
		'Content-Type': 'application/json'
		
	},
	body: JSON.stringify(newTodo)
})
.then(response => {
	if(!reponse.ok) {
		throe new Error(~~~)
		}
		return response.json()
})

function AddTodo() {
	const queryClient = useQueryClient()
	const mutation = useMutation(addTodo, {
		onSuccess: () => {
			queryCleint.invalidateQueries('todos')
		}
	})
}
const hadnleSumbit = (e) => {
	e.prventDefault()
	const newTodo = {title: e.target.todo.value, completed: false}
	mutation.mutate(newTodo)
}
 return (

   <form onSubmit={handleSubmit}>
     <input type="text" name="todo" />
     <button type="submit">Add Todobutton>
     {mutation.isLoading ? 'Adding todo...' : ''}
     {mutation.isError ? `An error occurred: ${mutation.error.message}` : ''}
     {mutation.isSuccess ? 'Todo added!' : ''}
   form>

 );

쿼리 무효화와 재용청

데이터가 변경되었을 때 관련된 쿼리를 자동으로 업데이트하는 데 사용 자동으로 새로고침 하는 경우 활용

const queryClient = useQueryClient()
//todos 쿼리 무효화
qyeryClient.invalidateQueries('todos')
// todos 쿼리가 무효화되고 백그라운드에서 새로운 데이터를 fetch함

에러 핸들링

const {isError, error} = useQuery('todos',fetchTodos, {
	rerty:3,
	onError: (error)=> {
		console.log('An error occurred:', error)
	}
})

if(isError) {
return <div>{error.message}</div>
}

심화버전

Query Key 관리

Query key는 리액트 쿼리에서 데이터를 식별하고 관리하는 핵심 요소로 복잡한 애플리케이션에서 데이터를 관리하고 업데이트하기 위해 중요하다.
즉 고유한 키로 쿼리를 식별하여 캐시가 관리된다.

// 단순 문자열 키
const {data: todos} = useQuery('todos', fetchTodos)

//배열 형태의 키
const {data: todo} = useQuery(['todo',5], ()=> fetchTodoById(5))
// 객체를 포함한 배열 키
const {data: doneTodos} = useQuery(['todos',{status:'done'}], ()=>
fetchTodosByStatus('done'))

페이지네이션과 무한스크롤

const {data, isLodaing, error, isPreviousData} = useQuery(
['todos',page],
()=> fetchTodoPage(page),
{keepPreviousData: true}
)
const {data, fetchNextPage,hadNextPage,isFetchingNextPage} = useInfiniteQuery('todos', fetchTods, {
	hetNextPageParam: (lastPage,pages) => lastPage.nextCursor
})

Prefetching 과 Optimistic Updates

Prefetching은 사용자 경험을 개선하기 위해 데이터를 미리 로드하는데 사용

const queryClient = useQueryClient();
queryClient.prefetchQuery('todos',fetchTodos)
//todos 데이터가 백그라운에서 미리 로드되어 캐시에 저장됨

Optimistic Updates는 서버 응답을 기다리지 않고 UI를 즉시 업데이트하는 기술입니다.

const queryClient = useQueryClient();

const mutation = useMutation(updateTodo, {
	onMutate: async(newTodo) => {
		await queryClient.cancelQueries('todos')
		const previousTodos = queryClient.getQueryData('todos')
		queryClient.setQueryData('todos', old => [...old, newTodo])
		return {previousTodos}
	}
	onError: [err, newTodo, context]=> {
	queryClient.setQueryData('todo', context.previousTodos
	)},
	onSettled: ()=> {
		queryClient.invalidateQueries('todos')
	}
})

// 변경 즉시 UI 업데이트
// 에러 시 이전 상태로 롤백
// 성공 여부와 관계없이 서버 데이터와 동기화

0개의 댓글

관련 채용 정보