728x90
반응형

로그인 회원가입을 위한 페이지를 세팅해보자. 먼저 index.tsx 파일을 수정해준다.

 

index.tsx

import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import styles from '../styles/Home.module.css'

const Home: NextPage = () => {
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to my Site!
        </h1>

        <div className={styles.grid}>
          <Link href={{
            pathname: '/auth/login'
          }}>
            <a className={styles.card}>
              <p>
                Login
              </p>
            </a>
          </Link>
          <Link href={{
            pathname: '/auth/signup'
          }}>
            <a className={styles.card}>
              <p>
                Signup
              </p>
            </a>
          </Link>
        </div>
      </main>

      <footer className={styles.footer}>
        <p>
        copyright © Teepo
        </p>
      </footer>
    </div>
  )
}

export default Home

 

실행해본다.

 

간단하게 Login, Signup 버튼이 나오고, Link href 옵션에 '/auth/login' 과 '/auth/signup' 을 써주었다.

 

이제 우린 auth라는 파일을 만들고 SSR로 받아오는 데이터를 읽어 어떤 컴포넌트를 보여줄 것인지 정의할 것이다. 

 

 

경로는 /auth/[cate].tsx가 되고, [cate].tsx 부분에 무슨 문자열이 오는지에 따라 다른 컴포넌트를 보여줄 것이다.

 

지금 상태에서 웹을 확인해보면

 

이런 문구가 뜰 것이다. [cate].tsx 파일을 수정해보자.

 

/pages/auth/[cate].tsx

import { GetServerSideProps, GetStaticPaths, GetStaticProps } from 'next'
import type { NextPage } from 'next'

interface Props {
    CateData : string
}

const Auth:NextPage<Props> = ({CateData}) => {
    console.log(CateData)
    return (
        <div className='auth'>
            {(CateData === 'login') ? "Login" : ""}
            {(CateData === 'signup') ? "Signup" : ""}
        </div>
        )
}


export default Auth;


export const getServerSideProps:GetServerSideProps = async (context) => {
    const CateData = context.query.cate;
    return {
        props: {
            CateData
        }
    }
}

 

getServerSideProps로 받아온 데이터의 cate 값을 읽어 어떤 문자열이 들어오는지 읽고,

삼항연산자로 문자열에 따라 보여줄 내용을 정의했다. 나중에 css 추가를 위해 className에 'auth'를 추가해주었다.

 

 

물론 각각 다른 파일들로 만드는 방법도 있다. 하지만 나는 로그인, 회원가입에서 Header를 같이 쓰고싶었기 때문에 

이렇게 구조를 정의했다.

 

이번엔 Component들을 만들어보자. 루트경로에 src 폴더와 하위에 component 폴더를 만들고 아래 파일들을 작성한다.

 

LoginComponent.tsx

import type { NextPage } from 'next'

interface Props {

}

const Login:NextPage<Props> = () => {
    return (
        <div className='auth'>
            Login
        </div>
        )
}


export default Login

 

SignupComponente.tsx

import type { NextPage } from 'next'

interface Props {

}

const Signup:NextPage<Props> = () => {
    return (
        <div className='auth'>
            Signup
        </div>
        )
}


export default Signup

 

이제 [cate].tsx 파일에서 컴포넌트를 사용해보자.

 

[cate].tsx

import { GetServerSideProps, GetStaticPaths, GetStaticProps } from 'next'
import type { NextPage } from 'next'
import LoginComponent from '../../src/components/LoginComponent'
import SignupComponent from '../../src/components/SignupComponent'


interface Props {
    CateData : string
}

const Auth:NextPage<Props> = ({CateData}) => {
    return (
        <div className='auth'>
            {CateData} page
            {(CateData === 'login') ? <LoginComponent /> : ""}
            {(CateData === 'signup') ? <SignupComponent /> : ""}
        </div>
        )
}


export default Auth;


export const getServerSideProps:GetServerSideProps = async (context) => {
    const CateData = context.query.cate;
    return {
        props: {
            CateData
        }
    }
}

 

Header에 쓰일 부분에 임의로 어떤 페이지인지 나타내주는 문구를 작성했다.

컴포넌트들이 잘 나타나는지 확인해본다.

 

 

 

728x90
반응형
728x90
반응형

나중에 프론트 쪽에서 할 상태관리를 위해 front폴더에 세팅을 해준다.

자세한 내용은 아래 링크에 접속하면 확인 가능하다.

https://typo.tistory.com/entry/Nextjs-next-redux-wrapper

 

Next.js | next-redux-wrapper

NextJS에서 상태를 관리하기 수월하게 해주는 redux를 TypeScript와 함께 사용해보자. 이 포스트는 counter에 대한 state를 다루는 포스트이다. 사전 준비 create-next-app으로 프로젝트를 생성한다. $ npx create.

typo.tistory.com

 

로그인에 관한 기본적인 세팅만 해주겠다.

 

1. 먼저 필요한 npm 모듈들을 설치하자.

$ npm i react-redux redux next-redux-wrapper redux-thunk @types/redux-promise @types/redux-logger
$ npm i redux-devtools-extension redux-logger --dev-save

 

2. 루트 디렉토리에 store폴더를 생성하고 아래와 같이 구조를 만들어준다.

3. 그다음 아래 코드들을 입력해준다.

user.interfaces.ts

export interface UserState {
    userInfo : UserInfo;
    islogined : boolean;
    loginError : '';
    signupDone : boolean;
    signupError : '';
    idDuple : boolean;
    emailDuple : boolean;
    emailAuth : boolean;
    data : any;
}

export interface UserInfo {
    id : string;
    pw : string;
    email : string;
    address : string;
}

입력값으로 쓰일 User interface와 함수실행 후 반환값으로 받을 값들을 선언해준다.

마지막 data 속성은 차후에 payload로 데이터를 받기위한 저장공간이다.

UserStateUser를 포함한다.

 

 

userAct.interfaces.ts

export enum actionTypesUser {
    USER_INIT = "USER_INIT", // state 초기화
}

export type ActionsUser = UserInit 

export interface UserInit {
    type : actionTypesUser.USER_INIT;
    data : any;
}

아직은 UserState를 초기화하는 actionType 밖에 없지만 차근차근 늘려나갈 것이다.

 

 

 

/store/interfaces/index.ts

export * from './user/user.interfaces'
export * from './user/userAct.interfaces'

4. user 인터페이스와 액트를 export한다.

 

/store/interfaces/RootState.ts

import { UserState } from './index'

export interface RootStateInterface {
    user : UserState;
}

5. UserState를 가져와 RootState에 넣어준다. ( 이곳은 모든 State를 포함합니다. )

 

/store/reducer/index.ts

import { combineReducers, Reducer, AnyAction } from "redux";
import { RootStateInterface } from "../interfaces/RootState";
import user from "./user_reducer";

const rootReducer: Reducer<
	RootStateInterface,
	AnyAction
> = combineReducers<RootStateInterface>({
	user,
});

export default rootReducer;
export type RootState = ReturnType<typeof rootReducer>;

RootState 폴더에 선언한 State들을 가져와서 Reducer와 엮어준다.

 

 

/store/reducer/user_reducer.ts

import { HYDRATE } from "next-redux-wrapper";
import { getFontDefinitionFromManifest } from "next/dist/server/font-utils";
import {
    UserState,
    UserInfo,
    actionTypesUser,
    ActionsUser
} from "../interfaces";

export const initialState : UserState = {
    userInfo : <UserInfo>{
        id : "",
        pw : "",
        email : "",
        address : ""
    },
    islogined : false,
    loginError : '',
    signupDone : false,
    signupError : '',
    idDuple : false,
    emailDuple : false,
    emailAuth : false,
    data : {}
}

interface HydratePayload {
    user : UserState
}

const user = (
    state = initialState,
    action : ActionsUser | { type : typeof HYDRATE; payload : HydratePayload }
) : UserState => {
    switch (action.type) {
        case HYDRATE:
            return { ...state, ...action.payload.user};
        case actionTypesUser.USER_INIT:
            return {
                ...state,
                userInfo : initialState.userInfo
            }
        default:
            return state
    }
}

export default user;

userinitialState를 정의해주고 dispatch가 실행됐을 때의 로직을 정의한다.

나중엔 action이 추가됨에 따라 reducer의 case도 늘어날 것이다.

 

 

/store/index.ts

import { createStore, applyMiddleware, compose } from "redux";
import { createWrapper } from "next-redux-wrapper";
import promiseMiddleware from 'redux-promise';
import ReduxThunk from 'redux-thunk';
import rootReducer from "./reducer";

const createStoreWithMiddleware = applyMiddleware(promiseMiddleware, ReduxThunk)(createStore)

const configureStore = () => {
	const store = createStoreWithMiddleware (rootReducer);
	return store;
};

const wrapper = createWrapper(configureStore, { debug: true });

export default wrapper;

store를 생성하고 _app.tsx에 쓰일 wrapper를 만들어준다.

 

 

/pages/_app.tsx

import { AppProps } from "next/app";
import { NextPage } from "next";
import wrapper from "../store"; // store.ts 파일

const MyApp: NextPage<AppProps> = ({ Component, pageProps }: AppProps) => {
	return (
		<>
			<Component {...pageProps} />
		</>
	);
};

export default wrapper.withRedux(MyApp);

_app.tsx 파일의 MyApp을 만들었던 wrapper로 감싸주면 store 설정이 끝난다.

 

마지막으로 tsconfig.json에 store부분을 추가해준다.

 

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx","store/**/*.ts"],
  "exclude": ["node_modules"]
}
728x90
반응형

+ Recent posts