Skip to content

Commit

Permalink
feat: zustand로 마이그레이션
Browse files Browse the repository at this point in the history
  • Loading branch information
JoStar33 committed Aug 20, 2024
1 parent 016e8a0 commit fd67fa3
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 109 deletions.
63 changes: 37 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
"react-hook-form": "^7.51.2",
"react-icons": "^5.0.1",
"react-router-dom": "^6.22.3",
"recoil": "^0.7.7",
"styled-components": "^6.1.8",
"styled-reset": "^4.5.2",
"use-mask-input": "^3.3.7",
"yet-another-react-lightbox": "^3.21.4",
"yup": "^1.4.0"
"yup": "^1.4.0",
"zustand": "^4.5.5"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
Expand Down
15 changes: 7 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import GlobalStyle from '@/styles/GlobalStyles';
import Theme from '@/styles/Theme';
import Layout from '@/components/layouts';
import { useRecoilValue } from 'recoil';
import { modalWithText } from '@/stores/modal';
import { useModalStore } from '@/stores/modal';
import Portal from '@/components/common/Portal';
import Modal from '@/components/common/Modal';
import { AnimatePresence } from 'framer-motion';
import Router from '@/Router';
import { loadingState } from './stores/loading';
import { useLoadingStore } from './stores/loading';
import Loading from './components/common/Loading';
import DarkBackground from './components/common/DarkBackground';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
Expand All @@ -16,9 +15,9 @@ import databaseInitializer from './mocks/fakeDatabase';
import React from 'react';

export default function App() {
const { isLoading } = useLoadingStore();
const { modalState } = useModalStore();
const queryClient = new QueryClient(queryClientDefaultOptions);
const modalWithTextValue = useRecoilValue(modalWithText);
const loadingValue = useRecoilValue(loadingState);

React.useEffect(() => {
databaseInitializer();
Expand All @@ -33,9 +32,9 @@ export default function App() {
</Layout>
<Portal>
<AnimatePresence>
{modalWithTextValue.type === 'ALERT' && <Modal.Alert />}
{modalWithTextValue.type === 'CONFIRM' && <Modal.Confirm />}
{loadingValue.isLoading && (
{modalState.type === 'ALERT' && <Modal.Alert />}
{modalState.type === 'CONFIRM' && <Modal.Confirm />}
{isLoading && (
<DarkBackground>
<Loading mode="fixed" />
</DarkBackground>
Expand Down
1 change: 1 addition & 0 deletions src/components/common/LabelWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default function LabelWrapper({ label, labelStyle, wrapperStyle, isHorizo
flexDirection: 'column',
gap: '10px',
};

return (
<S.LabelWrapper style={mainStyle}>
<p className="label-wrapper__label" style={labelStyle}>
Expand Down
27 changes: 13 additions & 14 deletions src/components/common/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import styled from 'styled-components';
import { motion } from 'framer-motion';
import { useRecoilValue } from 'recoil';
import Portal from '@/components/common/Portal';
import DarkBackground from '@/components/common/DarkBackground';
import { textEllipsis } from '@/styles/Common';
import { modalWithText } from '@/stores/modal';
import { useModalStore } from '@/stores/modal';
import { IoMdInformationCircleOutline } from 'react-icons/io';

const modalVariants = {
Expand All @@ -27,8 +26,8 @@ const modalVariants = {
};

function Alert() {
const modalValue = useRecoilValue(modalWithText);
const computedDescTextArr = modalValue.descText ? modalValue.descText.split('\n') : '';
const { modalState } = useModalStore();
const computedDescTextArr = modalState.descText ? modalState.descText.split('\n') : '';

return (
<Portal>
Expand All @@ -38,13 +37,13 @@ function Alert() {
<i className="info-icon">
<IoMdInformationCircleOutline size={30} fill="#57a8eb" />
</i>
<h3 className="title-text">{modalValue.titleText}</h3>
<h3 className="title-text">{modalState.titleText}</h3>
<div className="desc-text-container">
{computedDescTextArr ? computedDescTextArr.map((desc) => <p className="desc-text">{desc}</p>) : computedDescTextArr}
</div>
</div>
<button className="button-box__confirm" onClick={modalValue.onClickConfirm}>
{modalValue.confirmButtonText}
<button className="button-box__confirm" onClick={modalState.onClickConfirm}>
{modalState.confirmButtonText}
</button>
</S.Modal>
</DarkBackground>
Expand All @@ -53,8 +52,8 @@ function Alert() {
}

function Confirm() {
const modalValue = useRecoilValue(modalWithText);
const computedDescTextArr = modalValue.descText ? modalValue.descText.split('\n') : '';
const { modalState } = useModalStore();
const computedDescTextArr = modalState.descText ? modalState.descText.split('\n') : '';

return (
<Portal>
Expand All @@ -64,17 +63,17 @@ function Confirm() {
<i className="info-icon">
<IoMdInformationCircleOutline size={30} fill="#57a8eb" />
</i>
<h3 className="title-text">{modalValue.titleText}</h3>
<h3 className="title-text">{modalState.titleText}</h3>
<div className="desc-text-container">
{computedDescTextArr ? computedDescTextArr?.map((desc) => <p className="desc-text">{desc}</p>) : computedDescTextArr}
</div>
</div>
<div className="button-box">
<button className="button-box__cancel" onClick={modalValue.onClickCancel}>
{modalValue.cancelButtonText}
<button className="button-box__cancel" onClick={modalState.onClickCancel}>
{modalState.cancelButtonText}
</button>
<button className="button-box__confirm" onClick={modalValue.onClickConfirm}>
{modalValue.confirmButtonText}
<button className="button-box__confirm" onClick={modalState.onClickConfirm}>
{modalState.confirmButtonText}
</button>
</div>
</S.Modal>
Expand Down
6 changes: 2 additions & 4 deletions src/containers/signUp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ import SignUp from '@/components/signUp';
import routerPath from '@/constants/routerPath';
import { useErrorHandler } from '@/hooks/useErrorHandler';
import useLoading from '@/hooks/useLoading';
import { modalState } from '@/stores/modal';
import { useModalStore } from '@/stores/modal';
import { ISignUpForm } from '@/types/auth';
import { schema } from '@/utils/validate/schema';
import { yupResolver } from '@hookform/resolvers/yup';
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { useResetRecoilState, useSetRecoilState } from 'recoil';
import styled from 'styled-components';

export default function SignUpContainer() {
const { isLoading, setIsLoading } = useLoading();
const { handleError } = useErrorHandler();
const setModalState = useSetRecoilState(modalState);
const resetModalState = useResetRecoilState(modalState);
const { resetModalState, setModalState } = useModalStore();
const navigate = useNavigate();
const methods = useForm<ISignUpForm>({
defaultValues: {
Expand Down
8 changes: 4 additions & 4 deletions src/hooks/useErrorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { modalState } from '@/stores/modal';
import { useModalStore } from '@/stores/modal';
import { DefaultResponse } from '@/types';
import axios, { AxiosError } from 'axios';
import { useResetRecoilState, useSetRecoilState } from 'recoil';

export function useErrorHandler() {
const setModalState = useSetRecoilState(modalState);
const resetModalState = useResetRecoilState(modalState);
const { resetModalState, setModalState } = useModalStore();

const handleError = (error: any) => {
if (axios.isAxiosError(error)) {
return setModalState((prev) => ({
Expand All @@ -19,6 +18,7 @@ export function useErrorHandler() {
},
}));
}

const axiosError: AxiosError<DefaultResponse> = error;
const isConnectionRefusedError = error.code?.includes('ERR_NETWORK');
const isUnprocessableEntity = axiosError.response?.status === 422;
Expand Down
16 changes: 2 additions & 14 deletions src/hooks/useLoading.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
import { loadingState } from '@/stores/loading';
import React from 'react';
import { useRecoilState, useResetRecoilState } from 'recoil';
import { useLoadingStore } from '@/stores/loading';

export default function useLoading() {
const [loadingValue, setLoadingValue] = useRecoilState(loadingState);
const resetLoading = useResetRecoilState(loadingState);
const { isLoading, setIsLoading } = useLoadingStore();

const isLoading = loadingValue.isLoading;
const setIsLoading = (value: boolean) => setLoadingValue((prev) => ({ ...prev, isLoading: value }));

React.useEffect(() => {
return () => {
resetLoading();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return { isLoading, setIsLoading };
}
16 changes: 7 additions & 9 deletions src/stores/loading.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { atom } from 'recoil';
import recoilKeys from '@/constants/recoilKeys';
import { create } from 'zustand';

interface ILoadingState {
interface ILoadingStore {
isLoading: boolean;
setIsLoading: (isShow: boolean) => void;
}

export const loadingState = atom<ILoadingState>({
key: recoilKeys.LOADING,
default: {
isLoading: false,
},
});
export const useLoadingStore = create<ILoadingStore>((set) => ({
isLoading: false,
setIsLoading: (isShow: boolean) => set((state) => ({ ...state, isLoading: isShow })),
}));
50 changes: 22 additions & 28 deletions src/stores/modal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import recoilKeys from '@/constants/recoilKeys';
import { atom, selector } from 'recoil';
import { create } from 'zustand';

interface IModalState {
type?: 'ALERT' | 'CONFIRM';
Expand All @@ -11,31 +10,26 @@ interface IModalState {
onClickCancel: (...args: any) => void;
}

export const modalState = atom<IModalState>({
key: recoilKeys.MODAL,
default: {
type: undefined,
titleText: undefined,
descText: undefined,
confirmButtonText: '',
cancelButtonText: '',
onClickConfirm: () => {},
onClickCancel: () => {},
},
});
interface IModalStore {
modalState: IModalState;
setModalState: (fn: (prev: IModalState) => IModalState) => void;
resetModalState: () => void;
}

const initModalState = {
type: undefined,
titleText: undefined,
descText: undefined,
confirmButtonText: '',
cancelButtonText: '',
onClickConfirm: () => {},
onClickCancel: () => {},
};

export const modalWithText = selector({
key: recoilKeys.MODAL_WITH_TEXT,
get: ({ get }) => {
const getModalState = get(modalState);
return {
type: getModalState.type,
titleText: getModalState.titleText,
descText: getModalState.descText,
confirmButtonText: getModalState.confirmButtonText,
cancelButtonText: getModalState.cancelButtonText,
onClickConfirm: getModalState.onClickConfirm,
onClickCancel: getModalState.onClickCancel,
};
export const useModalStore = create<IModalStore>((set) => ({
modalState: initModalState,
setModalState: (fn: (prev: IModalState) => IModalState) => {
set((state) => ({ modalState: fn(state.modalState) }));
},
});
resetModalState: () => set((prev) => ({ ...prev, modalState: initModalState })),
}));

0 comments on commit fd67fa3

Please sign in to comment.