본문 바로가기

코드스테이츠 SEB FE 41기/Section 별 내용 정리

section2/Unit11/ Coz’ Mini Hackathon(10/18)

반응형

블로깅 주제

  • 나만의 아고라 스테이츠 만들기 - 서버 & 리액트 리팩토링

1. 지금 현재, 당신의 기분이나 느낌을 표현해 주세요.

  • 역시 솔로프로젝트는 뭐든 정신이 없다! 리액트로 리팩토링을 꼭 해보고싶었는데... 아직 리액트가 익숙치 않아서 그런가 시작하기가 어렵다.. 그래도 꼭 해내고싶다! 섹션2까지 고생한 나 자신... 멋지다^^

2. 오늘 무엇을 학습한 내용 중 지금 떠올릴 수 있는 단어를 모두 나열해 주세요.

  • 나만의 아고라 스테이츠 만들기 - 서버 & 리액트 리팩토링

3. 2에서 작성한 단어를 가지고, 오늘의 학습 내용을 설명해 보세요.

- 솔로 프로젝트 : 나만의 아고라 스테이츠 만들기 - 서버 & 리액트 리팩토링

 

헤매여서 시간을 쏟은 부분을 정리해보자.

 

※ params로 받아온 데이터의 value 값은 string 이다! 

findById: (req, res) => {
    // TODO: 요청으로 들어온 id와 일치하는 discussion을 응답합니다.
    const { id } = req.params; // id의 타입 : string
    let filteredDiscussion = discussionsData.filter((discussion) => {
      return discussion.id === Number(id); // Number 형태로 바꿔서 비교해야 함
    })
    if(filteredDiscussion.length !== 0){
      return res.status(200).send(filteredDiscussion[0]);
    }else{
      return res.status(404).send('Not Found!');
    }
  }

 

res.send()와 res.json()의 차이

body 데이터가 배열 또는 객체라면 자동으로 컨텐트 타입을 json 형태로 설정하여, 

JSON.stringfy 처리를 하지 않아도 자동으로 json 형태로 응답을 보낸다.

https://fansor.tistory.com/m/15

 

[express, nodejs] res.send() VS res.json() 그리고 res.end()

express를 쓰다보면 http요청을 받아 res라는 응답객체를 사용한다. 이 res를 이용해 여러 방식으로 클라이언트에게 응답을 보낸다. 오늘은 여러 방식중에서도 비슷한 세가지 방식(res.send, res.json 그

fansor.tistory.com


app.js

const express = require('express');
const app = express();

const cors = require('cors');
const morgan = require('morgan');

// morgan 미들웨어가 세팅되어 있습니다.
// HTTP 요청 logger를 편리하게 사용할 수 있는 미들웨어 입니다.
app.use(morgan('tiny'));

// TODO: cors를 적용합니다.
app.use(cors());
// TODO: Express 내장 미들웨어인 express.json()을 적용합니다.
app.use(express.json());

const port = 4000;
const discussionsRouter = require('./router/discussions');

// TODO: app.use()를 활용하여 /discussions 경로로 라우팅합니다. 
app.use('/discussions',discussionsRouter);

app.get('/', (req, res) => {
  // 서버 상태 확인을 위해 상태 코드 200과 함께 응답을 보냅니다.
  res.status(200).send('fe-sprint-my-agora-states-server');
});

const server = app.listen(port, () => {
  console.log(`[RUN] My Agora States Server... | http://localhost:${port}`);
});

module.exports.app = app;
module.exports.server = server;

 

discussions.js

// TODO: discussions 라우터를 완성합니다.
const { discussionsController } = require('../controller');
const { findAll, findById } = discussionsController;
const express = require('express');
const router = express.Router();

// TODO: 모든 discussions 목록을 조회하는 라우터를 작성합니다.
router.get('/',findAll);

// TODO: :id에 맞는 discussion을 조회하는 라우터를 작성합니다.
router.get('/:id',findById);

module.exports = router;

 

index.js

const { agoraStatesDiscussions } = require("../repository/discussions");
const discussionsData = agoraStatesDiscussions;

const discussionsController = {
  findAll: (req, res) => {
    // TODO: 모든 discussions 목록을 응답합니다.
    return res.status(200).send(discussionsData);
  },

  findById: (req, res) => {
    // TODO: 요청으로 들어온 id와 일치하는 discussion을 응답합니다.
    const { id } = req.params;//string
    let filteredDiscussion = discussionsData.filter((discussion) => {
      return discussion.id === Number(id);
    })
    if(filteredDiscussion.length !== 0){
      return res.status(200).send(filteredDiscussion[0]);
    }else{
      return res.status(404).send('Not Found!');
    }
  }
};

module.exports = {
  discussionsController,
};

 

섹션1에서 만들었던 나만의 아고라스테이츠와 연동!

 

script.js 하단에

fetch('http://localhost:4000/discussions')
.then(res => res.json())
.then(discussions => {
  agoraStatesDiscussions = discussions;
  // console.log(agoraStatesDiscussions);
  const ul = document.querySelector("ul.discussions__container");
  render(ul);
})

이 코드를 추가한 후, 상단에 agoraStatesDiscussions을 선언해준다.

let agoraStatesDiscussions;
이 때, 섹션1 솔로프로젝트 어드벤스드 과제인 로컬스토리지와 관련된 코드가 있으면 정상 작동되지 않는다.
로컬스토리지 부분의 코드를 없애주었더니 정상 작동된다.(이유는 모름..)
 
 

리액트로 리팩토링 해보기

 

리액트는 npm start를 해야 프로젝트가 열리는데... 난 계속 index.html 파일을 열어서 흰 화면만 보였던 것이였다...

이 문제로 어제, 오늘 총 이틀을 삽질을 했다는게 믿기지가 않는다^^ 진짜 나는 바보인가?? 왜 헷갈린거지...

어쨌든 우연찮게 다시 깨닫게 되어 다행이다 ㅠㅠ

 

리액트로 리팩토링하는 과정을 간단히 살펴보자.

1. 컴포넌트 별로 기능 나누기 

2. 섹션1에서 사용했던 파일 컴포넌트 별로 나눠 코드 작성하기(컴포넌트 총 세 개) 

3. 서버로부터 데이터 받아오기(useEffect) 

 

App.js

function App() {
  const [discussions, setDiscussions] = useState([]);

  useEffect(() => {
   fetch('http://localhost:4000/discussions') 
   .then(res => res.json())
   .then(data => {
    setDiscussions(data);
   })
  }, []);
  return (
    <div>
      <Form />
      <Discussions discussions={discussions}></Discussions>
    </div>
  );
}

리팩토링의 꽃... useEffect 부분을 다시 보자. 

fetch를 통해 '나만의 아고라 스테이츠 만들기 - 서버' 프로젝트에서 만든 서버를 가지고 온다.

discussions는 변하는 데이터이므로 state로 설정 후,  타 리소스에서 가져오는 데이터이므로 useEffect를 사용해준다.

처음 렌더링될 때만 데이터를 받아오면 되므로, dependency array에 []을 넣어준다.

Discussions 컨테이너에 props(props 이름: discussions)로  state 데이터인 discussions를 보내준다. 

 

Discussions.js

export const Discussions = ({discussions}) => {
return <section className="discussion__wrapper">
      <ul className="discussions__container">
        {discussions.map(discussion => {
          return <Discussion discussion={discussion} key={discussion.id} ></Discussion>
        })}
        </ul>
    </section>
}

map을 사용해 데이터를 뿌려주는 컨테이너이다. 

Discussion 컨테이너에 props로 배열 안에 있는 요소 하나하나들을 보내준다. 이때 key 값은 discussion의 id값을 사용한다.

 

Discussion.js

export const Discussion = ({discussion}) => {
    const {url, author, avatarUrl, title, createdAt, answer} = discussion;

    return (
        <li class="discussion__container">
          <div class="discussion__avatar--wrapper">
            <img class="discussion__avatar--image" src={avatarUrl} alt={`avatar of ${author}`}/>
          </div>
          <div class="discussion__content">
            <h2 class="discussion__title"><a href={url}>{title}</a></h2>
            <div className="discussion__information">{`${author} / ${new Date(createdAt).toLocaleString()}`}</div>
          </div>
          <div class="discussion__answered"><p className="discussion__isAnswered">{answer ?'☑' : '☒' }</p></div>
        </li>
    );
}

props로 받아온 데이터를 브라우저에 렌더링해주는 컨테이너이다. 

반응형