typescript로 useDispatch와 useSelector를 사용하기 위해 타입을 지정해주어야 한다.
먼저 store에서 각각 필요한 타입을 가져온다.
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
hooks > redux 파일에 생성한 타입을 각각 지정해준다.
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
// TypedUseSelectorHook를 사용하여 type 지정
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
사용할 때 useDispatch와 useSelector가 아닌, 타입을 지정한 useAppDispatch와 useAppSelector로 사용해준다.
const dispatch = useAppDispatch();
const { todos, isLoading, error } = useAppSelector((state) => state.todosSlice);
interface TodosType {
todos: Todo[];
editTitle: string;
isLoading: boolean;
error: unknown;
}
const initialState: TodosType = {
todos: [] as Todo[],
editTitle: "",
isLoading: true,
error: null,
};
const getTodosFromDB = async () => {
// <Todo[]>로 타입 지정
const { data } = await axios.get<Todo[]>(
`${process.env.REACT_APP_SERVER_URL}/todos`
);
return data;
};
export const __getTodos = createAsyncThunk(
"todos/getTodos",
async (_, thunkAPI) => {
try {
const todos = await getTodosFromDB();
return todos;
} catch (err) {
return thunkAPI.rejectWithValue(err);
}
}
);
extraReducers: (builder) => {
builder
.addCase(__getTodos.pending, (state) => {
state.isLoading = true;
})
.addCase(__getTodos.fulfilled, (state, action) => {
state.isLoading = false;
state.todos = action.payload;
})
.addCase(__getTodos.rejected, (state, action) => {
state.isLoading = false;
state.error = action.payload as string; // 타입 단언
})
import axios from "axios";
import { Todo } from "../types/todo";
// Promise<Todo[]>로 타입 정의
const getTodos = async (): Promise<Todo[]> => {
const { data } = await axios.get("http://localhost:4000/todos");
console.log(data);
return data;
};
// 매개변수의 타입과 리턴의 타입을 지정
// return이 없으므로 Promise<void>로 지정
const addTodo = async (newTodo: Todo): Promise<void> => {
await axios.post("http://localhost:4000/todos", newTodo);
};
const deleteTodo = async (id: string): Promise<void> => {
await axios.delete(`http://localhost:4000/todos/${id}`);
};
const toggleIsDoneTodo = async (payload: Todo): Promise<void> => {
console.log(payload);
await axios.patch(`http://localhost:4000/todos/${payload.id}`, {
isDone: !payload.isDone,
});
};
export { getTodos, addTodo, deleteTodo, toggleIsDoneTodo };
const { isLoading, isError, data } = useQuery("todos", getTodos, {
retry: 5,
});
const deleteMutation = useMutation(deleteTodo, {
onSuccess: () => {
queryClient.invalidateQueries("todos");
},
});
// useQuery
const {
isLoading,
error,
data: todos,
} = useQuery<Todo[], AxiosError<unknown, any>, Todo[], string[]>({
queryKey: ["todos"],
queryFn: getTodos,
retry: 5,
});
// Mutations
const deleteMutation = useMutation({
mutationFn: deleteTodo,
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
onError: (error: string) => {
console.error(error);
},
});