[Devlog] 메뉴 트리 동적 페이지 이동

Ahnjh·2022년 12월 11일
0

Devlog

목록 보기
6/11

지금까지는 단순히 메뉴트리를 보여주는것, 포스트 하나를 정적으로 보여주는작업을 했는데 실제 블로그에서 이런식으로 당연히 표현할 수 없기때문에 메뉴 클릭시 해당되는 포스트를 보여주는 작업을 할 것이다.
해당 작업에 대한 구조를 어떤식으로 짜야지 잘짰다고 생각이 들까 고민을 해봤다.

1. 각 포스트에 아이디를 줘서 해당 포스트로 이동

  • 그럼 포스트를 추가할때마다 아이디도 추가를 해줘야해서 비효율적이라 생각해 포기

2. 동적 라우팅 사용

  • 이방법이 깔끔할 것 같다

클릭 이벤트 추가

기존에 만들어 뒀던 MenuTree.js 에서 onClick 이벤트를 추가해주자

// MenuTree.js

<Link
  passHref
  key={index}
  href={{
    pathname: onClickFile(router, absFilePath, file, value[v]),
  }}
  >
  <MenuTreeFiles key={index} menuDepth={menuDepth}>
    {fileNameConverter(file)}
  </MenuTreeFiles>
</Link>
const onClickFile = (router, absFilePath, file, v) => {
    const filePath = "/" + findPath(absFilePath, "files", v) + "/" + file;
    
    router.push(filePath);
};

onClickFile 에서 findPath function 을 사용하고있는것을 볼 수 있는데 해당 로직은 아래와같이 생겼다.

const findPath = (ob, key, value) => {
    const path = [];
    const keyExists = (obj) => {
        if (!obj || (typeof obj !== "object" && !Array.isArray(obj))) {

            return false;
        } else if (obj.hasOwnProperty(key) && obj[key] === value) {

            return true;
        } else if (Array.isArray(obj)) {
            let parentKey = path.length ? path.pop() : "";

            for (let i = 0; i < obj.length; i++) {
                path.push(`${parentKey}[${i}]`);

                const result = keyExists(obj[i], key);
                if (result) {
                    return result;
                }

                path.pop();
            }
        } else {
            for (const k in obj) {
                path.push(k);

                const result = keyExists(obj[k], key);
                if (result) {
                    return result;
                }

                path.pop();
            }
        }

        return false;
    };

    keyExists(ob);

    return path.join("/");
}

전체 디렉토리 구조에서 파라미터로 받아온 value값이 있는곳까지의 경로를 path 배열에 집어넣고 path를 리턴해준다, 구분자는 "/"로 표현했다.

예시를 들어보자면 아래와 같은 구조가 있다고 가정할때

{
    "posts": {
        "back": {
            "express": {},
            "node": {}
        },
        "devops": {
            "aws": {},
            "docker": {}
        },
        "front": {
            "next": {},
            "react": {
                "files": [
                    "React_Hook_이란?.md",
                    "test.md"
                ],
                "tt": {}
            },
            "files": [
                "ts.md"
            ]
        },
        "temp": {
            "files": [
                "nonblocking.md"
            ]
        }
    }
}

해당 메뉴 클릭시 아래와 같은 경로가 나오게 된다
/posts/front/react/React\_Hook\_이란?.md

동적 라우팅 설정

// [...page].js
export default function Home() {
    const router = useRouter();

    const {page} = router.query;
    console.log(page);
    return (
        <Root>

        </Root>
    )
};

위와같이 파일을 만들어 준 후 메뉴를 클릭해보면 아래와 같이 정상적으로 이동이 되는것을 볼 수 있다.

[ "front", "react", "React_Hook_이란" ]

로그도 정상적으로 찍혀져 나온다. 이제 위의 경로를 가지고 해당 페이지에 포스팅 된 것을 보여줄 차례이다.

// [...page].js
const router = useRouter();
    const {page} = router.query;

    const [htmlContent, setHtmlContent] = useState();

    useEffect(() => {
        (async () => {
            try {
                const response = await axios.get("/api/markdown", {params: page});

                setHtmlContent(response?.data?.result);
            } catch (e) {
                console.log(e);
                return;
            }
        })();
    }, [router]);
    return (
        <Root>
            <div dangerouslySetInnerHTML={{ __html: htmlContent }}/>
        </Root>
    )

기존 devlog.js 페이지에서 사용하던 코드를 그대로 가져왔다. router.query로 받아온 값을 markdown.js api 에 넘겨주면. 아래와 같이 받아서 각 파일을 불러올 수 있다.

// markdown.js
const params = req.query;

const fileContent = getContent(params);
// markdown.js (func getContent)
const getContent = (params) => {
  let filePath = process.cwd() + '/posts';
  const paramKeys = Object.keys(params);

  paramKeys.map(v => {
    filePath += "/" + params[v];
  });

  const fileContents = fs.lstatSync(filePath).isDirectory() ? "" : fs.readFileSync(filePath, 'utf8');

  return fileContents;
};

그럼 아래와같이 메뉴 클릭시 동적으로 페이지 이동이 되는것을 볼 수 있다.

결과 :::

이렇게 해서 [...page].js 페이지 하나에서 모든 마크다운 파일들을 처리할 수 있게 되었다.

profile
Clean Code & Clean Architecture

0개의 댓글