일단 졸업프로젝트 멘토님이 먼저 제안해주셨다. 제안하시기 전에는 이런 라이브러리가 있는 줄도 몰랐다.
패기있게 한다고 말함. 일 벌이는거 제일 잘함.
근데 찾아보다보니까 장점이 많았다. 가장 큰 장점은
지금 코드 엄청 중구난방 난리다.
체계적으로 코드를 짜본 적이 없어서 그렇다..ㅎ 생각나는대로 쑤셔넣는다.
쨌든 React-Query는 코드를 확 줄여줄 수 있기 때문에 마음에 들었다.
그래서 일단 도전
😄
npm install -dev react-query
npm 명령어로 설치한다.
// App.tsx
import { QueryClientProvider, QueryClient } from 'react-query';
const queryClient = new QueryClient();
const App = () => {
...
return (
<QueryClientProvider client={queryClient}>
...
</QueryClientProvider>
)
}
가장 먼저 QueryClientProvider로 react-query를 적용하고자하는 컴포넌트들을 감싸준다.
<Route
path="/login"
element={
isLogin === true ? (
<Navigate replace to="/" />
) : (
<Login isLogin={isLogin} setIsLogin={() => setIsLogin} />
)
}
/>
그리고 redux로 관리했던 isLogin을 App에 선언하고 Login 등 다른 컴포넌트에 전달해서 사용할 수 있게 함
// lib/api/user.ts
export const login = async (user: UserType) => {
return client({
url: "/auth/login",
method: "post",
data: user,
})
.then((res) => {
const access_token = res.data.accessToken;
const token_exp = res.data.tokenExp;
cookies.set("access_token", access_token, {
path: "/",
expires: new Date(Date.now() + 1000 * 60 * 15),
});
return true;
})
.catch(() => {
return false;
})
};
// modules/user.ts
const [LOGIN, LOGIN_SUCCESS, LOGIN_FAILURE] =
createRequestActionTypes("user/LOGIN");
export const login = createRequestThunk(LOGIN, userAPI.login);
export default createReducer<UserReducer>(initialState, {
[LOGIN_SUCCESS]: (state, { payload: login }) => ({
...state,
login,
error: null,
}),
[LOGIN_FAILURE]: (state, { payload: error }) => ({
...state,
login: false,
error,
}),
});
// pages/Login.tsx
import { login } from '../modules/user';
const Login = () => {
...
const _handleSubmit = () => {
dispatch(login(user));
}
...
}
redux를 사용해서 상태 관리를 했던 이전 코드이다.
상태 관리에는 용이했지만 결과값을 dispatch를 호출한 컴포넌트에서는 볼 수 없고 module에서 처리해버려서 결과값 처리에 어려움이 좀 있었다.
그래서 react-query로 변환함
api 파일만 조금 수정하고 그대로 사용했다.
// lib/api/user.ts
export const login = async (user: UserType) => {
return client({
url: "/auth/login",
method: "post",
data: user,
});
};
// pages/Login.tsx
const Login = () => {
const mutationLogin = useMutation((user: UserType) => login(user));
...
const _handleSubmit = () => {
mutationLogin
.mutateAsync(user)
.then((res) => {
if (res.data.success) {
setIsLogin(true);
setToken(res.data.data);
}
})
.catch(() => {
setErrorMsg("로그인에 실패했습니다");
});
};
...
}
import { load } from '../lib/api/media';
...
const Mypage = () => {
const { status, data } = useQuery(["loadMedia"], () => load(""));
const renderByStatus = useCallback(() => {
switch (status) {
case "loading":
return (
<LoadingContainer>
<Spin
tip="Loading..."
indicator={<LoadingOutlined style={{ fontSize: 50 }} />}
/>
</LoadingContainer>
);
case "error":
return <ErrorPage />;
default:
return (
<Row gutter={[16, 16]} style={{ marginTop: "30px" }}>
{data?.data?.map((video: VideoType) => (
<StyledLink to="/result" key={video.id}>
<Col
id={String(video.id)}
style={{ display: "flex", width: 460 }}
>
<img
alt={String(video.id)}
height="160"
src="src"
/>
<VideoTitle>{video.videoName}</VideoTitle>
</Col>
</StyledLink>
))}
</Row>
);
}
}, [data?.data, status]);
return (
<Container>
<h2 style={{ fontWeight: "bold" }}>자막이 생성된 미디어</h2>
{renderByStatus()}
</Container>
);
};
export default Mypage;
아직 백엔드가 완성되지 않아서 MyPage에서는 api 호출을 못해보지만 일단 이렇게 바꿔뒀다.
src
├─ components
│ └─ Header.tsx
│
├─ interfaces
│ └─ interface.ts
│
├─ lib
│ └─ api
│ ├─ client.ts
│ ├─ media.ts
│ └─ user.ts
│
├─ pages
│ ├─ ErrorPage.tsx
│ ├─ Loading.tsx
│ ├─ Login.tsx
│ ├─ MainPage.tsx
│ ├─ MyPage.tsx
│ ├─ ResultPage.tsx
│ └─ Signup.tsx
│
├─ App.tsx
├─ config.ts
└─ index.tsx
js 파일들을 모두 tsx로 변경하고 redux를 처리하던 modules 폴더를 삭제했다.
modules 내에 코드가 많이 더러웠는데 이제야 조금 깔끔? 해진 것 같아서 마음에 든다.
😉