• [글또 10기 - 4] 백엔드 개발자가 처음해보는 리액트 프론트엔드 개발 - 마크다운 렌더링 페이지 개발
    개발공부/무작정만들어보자 2024. 11. 24. 20:03
    반응형

     지난번 글([글또 10기 - 3])에서 사이드바 css와  컴포넌트를 추가했다. 전체 구조는 다음과 같다. 사이드바를 구성했으니 이번에는 마크다운을 렌더링 할 수 있는 페이지를 추가해보려고 한다.

    Root 폴더
    +--- .next
    +--- public
    +--- src
          \---app
               \---module
                     \---Sidebar.module.css  # 사이드바 css              
               +---Sidebar.tsx # 사이드바 컴포넌트
               +---globals.css  # 글로벌 css
               +---layout.tsx   # 전체 레이아웃
               \---page.tsx     # 첫 번째 페이지
    +--- .eslintrc.json
    +--- .gitignore
    +--- next-env.d.ts
    +--- next.config.js
    +--- package-lock.json
    +--- package.json           # 라이브러리 버전(react: ^18,react-dom: ^18, next: 13.5.7)
    +--- postcss.config.js
    +--- README.md
    +--- tailwind.config.ts 
    \--- tsconfig.json          # alias 파일

     

     

     

    1. 리액트 마크다운 라이브러리

    기존 블로그가 마크다운으로 개발되어 있기 때문에, 최대한 마크다운을 사용하려고 한다. 어렵지 않게 리액트의 마크다운 렌더링 라이브러리를 찾을 수 있었다. 스타 수도 13.3k고, 최근까지 커밋이 있었다. 하지만, 최신 버전(9.0.1)이 2023년 11월인 것이 문제가 됐다.

     

    GitHub - remarkjs/react-markdown: Markdown component for React

    Markdown component for React. Contribute to remarkjs/react-markdown development by creating an account on GitHub.

    github.com

     

     우리는 사용 예제를 보고 따라하면, 즉각 기능이 동작하길 바라지만, 항상 그렇지 않다. 처음 배우는 모든 것이 그렇겠지만, 버전이 바뀌면서 어떤 부분이 잘못되어 컴파일이 실패하는지 알아내는 것은 쉽지 않다.

     

     

    찾아보니, 리액트 마크다운 라이브러리의 공식 페이지의 사용 예제는 "리액트 17"버전이다. 우리는 "리액트 18"버전을 사용하고 있다.

    // 리액트 17
    import React from 'react'
    import { createRoot } from 'react-dom/client'
    import Markdown from 'react-markdown'
    
    const markdown = '# Hi, *Pluto*!'
    
    createRoot(document.body).render(<Markdown>{markdown}</Markdown>)

     

     

     

    리액트 17과 18의 차이는 createRoot가 deprecate되었다는 것이다. 전체적인 페이지 구성이 많이 달라졌다.

    // 리액트 18
    import ReactMarkdown from 'react-markdown'
    
    const markdown = '# Hi, *Pluto*!'
    
    export default function Glossary() {
        return (
            <ReactMarkdown>{markdown}</ReactMarkdown>
        );
    }

    수정해서 실행하니 잘 됐다.

     

     

     

     

     

    2. 페이지 만들기

     폴더 전체 구성은 사이드바의 각 항목을 pages아래 폴더로 매칭하기로 했다.  기존 블로그의 "우선 용어사전 및 규칙" 항목을 만들려고 한다. 용어사전 및 규칙 항목은 페이지 하나로 구성되어있기 때문에, "pages/glossary/page.tsx" 파일만 생성했다.

     

    Root 폴더
    ...
    +--- src
          \---app
               ...
               \---pages
                     \---glossary
                            \--- page.tsx
               ...
    ...

     

    우선, 리액트 마크다운 라이브러리에 사용된 내용을 참고하여, 마크다운 내용을 파일에 넣었다. 

    // @/app/pages/glossary/page.tsx 파일
    
    import ReactMarkdown from 'react-markdown';
    import MainSidebar from '@/app/Sidebar';
    
    const markdownText = `
    ...
    6. 제목은 한글 영문 병기한다. 한글(영문)
    7. 쿠버네티스 관련 내용은 ["쿠버네티스 문서 한글화 가이드"](https://kubernetes.io/ko/docs/contribute/localization_ko/)를 따른다.
    8. :는 한글에서 사용하지 않으므로 .으로 대체한다.
    
    - Gradle 그레이들
    - Plugin 플러그인
    ...
    `;
    
    export default function Glossary() {
        return (
            <div>
                <MainSidebar />
                <ReactMarkdown>{markdownText}</ReactMarkdown>
            </div>
        );
    }

     

    다음으로 사이드바를 수정했다. 

    // ./module/Sidebar.tsx
    
    import Link from 'next/link';
    import styles from './Sidebar.module.css';
    
    const Sidebar: React.FC = () => {
      return (
        <div className={styles.sidebar}>
          <ul>
            ...
            <li>
              <Link href="/pages/glossary">용어 사전 및 규칙</Link>
            </li>
          </ul>
        </div>
      );
    };

     

    내가 원한 것은 왼쪽에 사이드바가 뜨고, 오른쪽에 페이지가 나오는 것이다. 하지만, 페이지를 확인해보니 사이드바 아래 페이지가 나왔다.

     

    div는 default 값이 "display:block" 이기 때문에 "display:flex"를 설정해줘야 자식 요소가 오른쪽으로 쌓인다. 그렇기 때문에 div에 style을 다음과 같이 변경한다. 이 부모요소(div)를 플렉스 컨테이너(Flex Container)라 부르고, 자식요소를 플렉스 아이템(Flex Item)이라고 부른다.

    // @/app/pages/glossary/page.tsx 파일
    
    import ReactMarkdown from 'react-markdown';
    import MainSidebar from '@/app/Sidebar';
    
    const markdownText = `
    ...
    6. 제목은 한글 영문 병기한다. 한글(영문)
    7. 쿠버네티스 관련 내용은 ["쿠버네티스 문서 한글화 가이드"](https://kubernetes.io/ko/docs/contribute/localization_ko/)를 따른다.
    8. :는 한글에서 사용하지 않으므로 .으로 대체한다.
    
    - Gradle 그레이들
    - Plugin 플러그인
    ...
    `;
    
    export default function Glossary() {
        return (
            <div style={{ display: 'flex' }}>
                <MainSidebar />
                <ReactMarkdown>{markdownText}</ReactMarkdown>
            </div>
        );
    }

     

    위와 같이 처리했을 때, 한 가지 문제가 또 발생한다. 원하지 않는 자식요소까지 플렉스 아이템이 되어 오른쪽으로 나열된다.

     

    플렉스 컨테이너의 영향을 받지 않게 하기 위해서는 div로 한 번 더 감싸줘야한다. div의 기본값이 "display: 'block'"이기 때문에, 별도 style을 적용해주지 않아도 된다.

    // @/app/pages/glossary/page.tsx 파일
    
    import ReactMarkdown from 'react-markdown';
    import MainSidebar from '@/app/Sidebar';
    
    const markdownText = `
    ...
    6. 제목은 한글 영문 병기한다. 한글(영문)
    7. 쿠버네티스 관련 내용은 ["쿠버네티스 문서 한글화 가이드"](https://kubernetes.io/ko/docs/contribute/localization_ko/)를 따른다.
    8. :는 한글에서 사용하지 않으므로 .으로 대체한다.
    
    - Gradle 그레이들
    - Plugin 플러그인
    ...
    `;
    
    export default function Glossary() {
        return (
            <div style={{ display: 'flex' }}>
                <MainSidebar />
                <div>
                   <ReactMarkdown>{markdownText}</ReactMarkdown>
                </div>
            </div>
        );
    }

     

    여기서 리액트 모듈로 css를 처리할 수 있게, 리팩토링해보자. 

    Root 폴더
    ...
    +--- src
          \---app
               \---module
                     \---Sidebar.module.css  # 사이드바 css 
                     \---Contents.module.css # 내용 페이지 css
               \---pages
                     \---glossary
                            \--- page.tsx
    ...

     

    Contents.module.css 파일을 생성한다.

    // @/app/module/Contents.module.css 파일
    
    .container {
      display: flex;
    }

     

    styles를 추가해주고, div의 style옵션을 className으로 변경한다.

    // @/app/pages/glossary/page.tsx 파일
    
    import ReactMarkdown from 'react-markdown';
    import MainSidebar from '@/app/Sidebar';
    import styles from '@/app/module/Contents.module.css';
    
    const markdownText = `
    ...
    6. 제목은 한글 영문 병기한다. 한글(영문)
    7. 쿠버네티스 관련 내용은 ["쿠버네티스 문서 한글화 가이드"](https://kubernetes.io/ko/docs/contribute/localization_ko/)를 따른다.
    8. :는 한글에서 사용하지 않으므로 .으로 대체한다.
    
    - Gradle 그레이들
    - Plugin 플러그인
    ...
    `;
    
    export default function Glossary() {
        return (
            <div className={styles.container}>
                <MainSidebar />
                <div>
                   <ReactMarkdown>{markdownText}</ReactMarkdown>
                </div>
            </div>
        );
    }

     

     

    3. 용어사전 및 규칙 페이지 완성

    반응형

    댓글

Designed by Tistory.