TypeScript : 투두리스트 만들기 (5단계 - React Query + Axios )

728x90
반응형

 

TypeScript : 투두리스트 만들기 (4단계 - Thunk + Axios )

TypeScript : 투두리스트 만들기 (3단계 - Json-server) TypeScript : 투두리스트 만들기 (2단계 - Redux Toolkit) TypeScript : 투두리스트 만들기 (1단계 - React Props) Lv1 React를 이용한 TodoList를 만듭니다. Todo를 Create,

zerotonine2da.tistory.com

Lv5

  • Lv4의 과제에서 Redux를 react-query로 리팩토링 합니다.

Keyword

query


1. React-Query 설치

yarn add react-query

 

2. index.tsx

import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import GlobalStyle from './GlobalStyles';

import { QueryClient, QueryClientProvider } from 'react-query';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

const queryClient = new QueryClient();

root.render(
    <QueryClientProvider client={queryClient}>
        <GlobalStyle />
        <App />
    </QueryClientProvider>
);

1) QueryClinetProvider 설정

 

▼참고

 

React : React Query + Axios ( 데이터 조회 + 추가 )

React Query 1. 기존 미들웨어의 한계 (Redux-Thunk) 보완 : 보일러 플레이트 => 코드량이 너무 많음 : Redux가 비동기 데이터 관리를 위한 전문 라이브러리가 아님 2. 강점 : 사용 방법이 쉽고 직관적임 : 보

zerotonine2da.tistory.com

3. src > queryApi.ts

import api from './api';
import { Todo } from '../types/Todo';
//조회
const getTodos = async () => {
    const response = await api.get('/todos');
    return response.data;
};

//추가
const addTodos = async (newData: Todo) => {
    await api.post(`/todos/`, newData);
};

//삭제
const deleteTodos = async (id: string) => {
    await api.delete(`/todos/${id}`);
};

//변경
const changeTodos = async ({ id, isDone }: { id: string; isDone: boolean }) => {
    await api.patch(`/todos/${id}`, { isDone: !isDone });
};

export { getTodos, addTodos, deleteTodos, changeTodos };

1) 변경 부분 : 객체 하나로 묶어서 전달

 

4. src > InputForm.tsx (추가)

import React, { useState } from 'react';
import uuid from 'react-uuid';
import styled from 'styled-components';
import { useMutation, useQueryClient } from 'react-query';
import { addTodos } from '../axios/queryApi';

function InputForm() {
    const queryClient = useQueryClient();
    const mutation = useMutation(addTodos, {
        onSuccess: () => {
            queryClient.invalidateQueries('todos');
        },
    });

    const [title, setTitle] = useState<string>('');
    const [content, setContent] = useState<string>('');

    const inputTitle = (e: React.ChangeEvent<HTMLInputElement>) => {
        setTitle(e.target.value);
    };

    const inputContent = (e: React.ChangeEvent<HTMLInputElement>) => {
        setContent(e.target.value);
    };

    const formSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        if (title === '' || content === '') {
            alert('제목/내용 모두 입력해야합니다.');
            return;
        }

        const newData = {
            id: uuid(),
            title,
            content,
            isDone: false,
        };
        mutation.mutate(newData);
        setTitle('');
        setContent('');
    };
    return (
        <StForm onSubmit={formSubmit}>
            <label>제목</label>
            <input value={title} onChange={inputTitle}></input>
            <label>내용</label>
            <input value={content} onChange={inputContent}></input>
            <button type="submit">추가하기</button>
        </StForm>
    );
}

export default InputForm;

1) useQueryClient()

2) useMutation()

3) mutation.mutate(새로운 데이터)

 

5. src > Content.tsx (삭제,변경,조회)

import React from 'react';
import styled from 'styled-components';
import { Todo } from '../types/Todo';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { changeTodos, deleteTodos, getTodos } from '../axios/queryApi';

type Props = {
    isDone: boolean;
};

function Content({ isDone }: Props) {
    const { isLoading, isError, data } = useQuery('todos', getTodos);

    const queryClient = useQueryClient();
    const mutationDelete = useMutation(deleteTodos, {
        onSuccess: () => {
            queryClient.invalidateQueries('todos');
        },
    });
    const mutationChange = useMutation(changeTodos, {
        onSuccess: () => {
            queryClient.invalidateQueries('todos');
        },
    });

    if (isLoading) {
        return <div>로딩중..</div>;
    }

    if (isError) {
        return <div>오류가 발생했습니다</div>;
    }
    const removeHandler = async (e: React.MouseEvent<HTMLButtonElement>, id: string) => {
        try {
            mutationDelete.mutate(id);
        } catch (error) {
            console.log('삭제 오류', error);
        }
    };

    const changeHandler = async (e: React.MouseEvent<HTMLButtonElement>, id: string, isDone: boolean) => {
        try {
            mutationChange.mutate({ id, isDone });
        } catch (error) {
            console.log('상태 업데이트 오류', error);
        }
    };

    return (
        <>
            <StDiv> {isDone ? '✌️Done✌️' : '✍️Working'}</StDiv>
            <StDivLayout>
                {data
                    .filter((item: Todo) => item.isDone === isDone)
                    .map((todo: Todo) => {
                        return (
                            <StDivTodo key={todo.id}>
                                <h3>{todo.title}</h3>
                                <p>{todo.content}</p>

                                <StDivBtn>
                                    <DeleteButton
                                        onClick={(e: React.MouseEvent<HTMLButtonElement>) => removeHandler(e, todo.id)}
                                    >
                                        삭제
                                    </DeleteButton>
                                    <StateButton
                                        onClick={(e: React.MouseEvent<HTMLButtonElement>) =>
                                            changeHandler(e, todo.id, todo.isDone)
                                        }
                                    >
                                        {isDone ? '취소' : '완료'}
                                    </StateButton>
                                </StDivBtn>
                            </StDivTodo>
                        );
                    })}
            </StDivLayout>
        </>
    );
}

export default Content;

1) useQuery()

2) useMutation

3) data.filter(타입설정) .map( 타입설정)

 

끝.

 

 

반응형