인프런 커뮤니티 질문&답변

반가우면반갑다고해님의 프로필 이미지
반가우면반갑다고해

작성한 질문수

React로 NodeBird SNS 만들기

페이지형 게시판 만들고있습니다.

작성

·

685

0

강의에서 배운걸 토대로 플젝중입니다.  게시판을 불러오는거는 성공했으나 ( 7개 불러오고싶으면 7개만 불러옴)

페이지형 게시판은 어떻게 구현해야하는지 감이 안잡힙니다.. ( 약 3일동안 작업했으나 결과물은 0이네요...)

여러 삽질중 알게된건데, 넥스트가 현재 동적데이터를 처리할 수 있게끔 Router()를 제공해준다고하네요 그렇지만  강의를 토대로 프로젝트를 하는거니 강의방식에 맞추고있습니다.

현재 프론트에서 express를 입혀주었고, 프론트 서버 라우터 경로는 

  server.get("/posts/:id", (reqres=> {
    return app.render(reqres"/board", { id: req.params.id });
 });

이렇게, 사가에서 axios를 이용해서 /posts/:id로 경로를 보내주면 pages/board로 랜더되게끔 경로를 해주었고

front =>pages/board.js 는 아래 하단의 깃허브 코드와 같이 해줬습니다.

https://github.com/wjdwndtlr/react-site/blob/master/front/pages/board.js

front=>reducers/post.js

https://github.com/wjdwndtlr/react-site/blob/master/front/reducers/post.js

front=>sagas=> post.js

https://github.com/wjdwndtlr/react-site/blob/master/front/sagas/post.js

back=>routes => posts.js

https://github.com/wjdwndtlr/react-site/blob/master/back/routes/posts.js

_app

https://github.com/wjdwndtlr/react-site/blob/master/front/pages/_app.js

현재 상태는 1~4번을 한번 눌렀을때 url이 NaN으로 나온다는것과 ( 두번누르면 제대로 나옵니다.)

리액트데브툴즈에서 데이터를 성공적으로 불러왔지만 1~4번을 눌러도 계속 똑같은 데이터를 불러오고 화면에 게시글출력이 똑같습니다.

질문을 썜이 더 보기좋게 하고싶었지만 이게 최선이였습니다. 링크를 타고 깃허브로 가야한다는 번거로움이 있지만요 ㅠㅠ

사실 이 글을 쓰기까지 세네번 질문을 올렸다 삭제했었습니다. 이유는 혼자했을때 잘안되면 바로 남에게 도움을 요청하는거같고, 너무 남의 도움에 의존하는거같아 혼자 해결하려했습니다..만 삼일이란 시간동안 하루 일곱시간 이상씩 붙잡고했지만 잘 안되어서 이정도면 충분히 시도해봤다싶어서 도움요청합니다...부탁드려요!! ㅠ ㅠ

답변 2

0

말씀하신대로 page로 바꿧습니다.

아래 사진에서처럼 데이터는 잘 불러옵니다만..2번을 누르든,3번을누르든 어느 숫자든 똑같은 게시글만을 출력합니다..

- Front => server.js

 server.get("/posts/:page", (reqres=> {
    return app.render(reqres"/board", { page: req.params.page });
  });

- border.js

import React, { useEffectuseState } from "react";
import styled from "styled-components";
import Link from "next/link";
import PropTypes from "prop-types";
import { media } from "../components/StyleUtils";
import { useDispatchuseSelector } from "react-redux";
import { LOAD_MAIN_POSTS_REQUEST } from "../reducers/post";

const Board = ({ page }) => {
  const { me } = useSelector(state => state.user);
  const { mainPosts } = useSelector(state => state.post);

  const dispatch = useDispatch();

  // 게시판 불러오기
  useEffect(() => {
    dispatch({
      type: LOAD_MAIN_POSTS_REQUEST
    });
  }, [page]);

  return (
    <>
      <PageTitle>
        <h1>자유게시판</h1>
        <h4>자유롭게 글을 쓸 수 있는 게시판입니다.</h4>
      </PageTitle>

      <Container>
        <Table>
          <thead>
            <tr>
              <Th style={width: 70 }}>NO</Th>
              <Th style={width: 500 }}>글제목</Th>
              <Th style={width: 120 }}>작성자</Th>
              <Th style={width: 100 }}>조회수</Th>
              <Th style={width: 100 }}>작성일</Th>
            </tr>
          </thead>
          {/* 글 리스트 */}

          <tbody>
            {mainPosts.map(c => {
              return (
                <tr key={c.id}>
                  <Td style={width: 70 }}>{c.id}</Td>
                  <Link href="/detail">
                    <Td style={width: 500 }}>{c.title}</Td>
                  </Link>
                  <Td style={width: 120 }}>{c.User.nickname}</Td>
                  <Td style={width: 100 }}>{c.views}</Td>
                  <Td style={width: 100 }}>{c.createdAt.substring(010)}</Td>
                </tr>
              );
            })}
          </tbody>
        </Table>

        <Ul>
          <Li>
            <Link
              href={pathname: "/board"query: { page: "1" } }}
              as={`/board/${page}`}
            >
              <ALink>1</ALink>
            </Link>
          </Li>
          <Li>
            <Link
              href={pathname: "/board"query: { page: "2" } }}
              as={`/board/${page}`}
            >
              <ALink>2</ALink>
            </Link>
          </Li>
          <Li>
            <Link
              href={pathname: "/board"query: { page: "3" } }}
              as={`/board/${page}`}
            >
              <ALink>3</ALink>
            </Link>
          </Li>
          <Li>
            <Link
              href={pathname: "/board"query: { page: "4" } }}
              as={`/board/${page}`}
            >
              <ALink>4</ALink>
            </Link>
          </Li>
        </Ul>
      </Container>

      {me && (
        <ButtonContainer>
          <Link href="/postForm">
            <a>
              <Button>글쓰기</Button>
            </a>
          </Link>
        </ButtonContainer>
      )}
    </>
  );
};

Board.getInitialProps = async context => {
  console.log("Board getInitialProps"context.query.page);
  return { page: context.query.page };
};

export default Board;

- reducers/post.js 

    case LOAD_MAIN_POSTS_REQUEST:
    case LOAD_USER_POSTS_REQUEST: {
      return {
        ...state,
        mainPosts: []
      };
    }
    case LOAD_MAIN_POSTS_SUCCESS:
    case LOAD_USER_POSTS_SUCCESS: {
      return {
        ...state,
        mainPosts: action.data,
        loading: false
      };
    }
    case LOAD_MAIN_POSTS_FAILURE:
    case LOAD_USER_POSTS_FAILURE: {
      return {
        ...state
      };
   }

-sagas/ post.js

// 글 불러오기
function loadMainPostsAPI(page) {
  return axios.get(page ? `/posts/${page}` : "/posts/");
}

function* loadMainPosts(action) {
  try {
    const result = yield call(loadMainPostsAPIaction.data);
    yield put({
      type: LOAD_MAIN_POSTS_SUCCESS,
      data: result.data
    });
  } catch (e) {
    yield put({
      type: LOAD_MAIN_POSTS_FAILURE,
      error: e
    });
  }
}

function* watchLoadMainPosts() {
  yield takeLatest(LOAD_MAIN_POSTS_REQUESTloadMainPosts);
}

- Back => posts.js

const express = require("express");
const db = require("../models");

const router = express.Router();

router.get("/"async (reqresnext=> {
  // GET //api/posts 게시글 가져오는것
  try {
    const posts = await db.Post.findAll({
      // pagination
      limit: 7,
      include: [
        {
          model: db.User,
          attributes: ["id""nickname"]
        }
      ],
      order: [["createdAt""DESC"]] // DESC는 내림차순, ASC는 오름차순
    });

    return res.json(posts);
  } catch (e) {
    console.error(e);
  }
});

router.get("/:page"async (reqresnext=> {
  // GET //api/posts 페이징형 게시글 가져오는것
  try {
    let pageNum = req.query.page// 요청 페이지 넘버
    let offset = 0;
    console.log("req.query.page:"req.query.page);
    if (pageNum > 1) {
      offset = 7 * (pageNum - 1);
    }

    const posts = await db.Post.findAll({
      // pagination
      offset: offset,
      limit: 7,
      include: [
        {
          model: db.User,
          attributes: ["id""nickname"]
        }
      ],
      order: [["createdAt""DESC"]] // DESC는 내림차순, ASC는 오름차순
    });

    return res.json(posts);
  } catch (e) {
    console.error(e);
    next(e);
  }
});

module.exports = router;

혹시 여기서 더 만져야 할 부분이있을까요?

useEffect에 굳이 LOAD_MAIN_POSTS_REQUEST.를 사용안해도된다고하셨는데 getInitialProps.에 사용하려면 어떻게해야하는지몰라 일단 useEffect에 사용했고, page 값이 바뀔때마다 리랜더링되게끔 []에 page를 넣어줬습니다.

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

답변이 조금 늦었습니다. 일단 req.query.id대신에 req.query.page같은 정확한 의미를 가진 단어를 써주세요. 너무 헷갈립니다.

그리고 useEffect 부분에서 LOAD_MAIN_POSTS_REQUEST와 LOAD_MAIN_POSTS_LIST_REQUEST를 왜 두번 호출하시는 지를 모르겠습니다. 둘의 역할이 같은 것 같은데 둘 중에 나중에 호출되는게 앞의 것을 덮어씌울 것입니다.

그리고 useEffect를 사용할 필요 없이 board에서 getInitialProps에서 LOAD_MAIN_POSTS_REQUESET 하셔도 됩니다. context안에 dispatch랑 id 둘 다 들어있으니까요.

반가우면반갑다고해님의 프로필 이미지
반가우면반갑다고해

작성한 질문수

질문하기