ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,12 @@
+import PageHandler from './PageHandler';
+import { getPopularMovie } from '../api/movie';
+
+export async function getNextPopularMovieList() {
+  const { page, done } = PageHandler.next();
+  const { results } = await getPopularMovie(page);
+  return {
+    page,
+    done,
+    nextMovieList: results,
+  };
+}

리뷰: `onClickMoreButton`을 `getNextPopularMovieList`로 변경하면서 역할을 분리해보았습니다!
@@ -0,0 +1,42 @@
+const MOVIE_TOTAL_PAGE_LIMIT = 500;
+
+const INITIAL_VALUE = {
+  page: 1,
+  totalPages: MOVIE_TOTAL_PAGE_LIMIT,
+};
+
+function PageEventHandler() {
+  let attr = { ...INITIAL_VALUE };
+
+  return {
+    next() {
+      if (!this.hasNextPage()) {
+        return {
+          page: attr.page,
+          done: true,
+        };
+      }
+      attr.page = attr.page + 1;
+
+      return {
+        page: attr.page,
+        done: !this.hasNextPage(),
+      };
+    },
+    getCurrentPage() {
+      return attr.page;
+    },
+    setTotalPages(totalPages) {
+      if (totalPages > MOVIE_TOTAL_PAGE_LIMIT) {
+        return;
+      }
+      attr.totalPages = totalPages;
+    },
+    hasNextPage() {
+      return attr.page < attr.totalPages;
+    },
+  };
+}
+
+const PageHandler = PageEventHandler();
+export default PageHandler;

리뷰: 제거하였습니다! 이유는 앞서 말씀드린 이유와 동일합니다!
꼼꼼히 리뷰해주셔서 감사드립니다 🙇
@@ -0,0 +1,12 @@
+import PageHandler from './PageHandler';
+import { getPopularMovie } from '../api/movie';
+
+export async function getNextPopularMovieList() {
+  const { page, done } = PageHandler.next();
+  const { results } = await getPopularMovie(page);
+  return {
+    page,
+    done,
+    nextMovieList: results,
+  };
+}

리뷰: 음... 이 부분은 제가 의도한 바와는 조금 다르게 변경된 것 같습니다!
제가 의사 코드를 섞어가며 어느 정도 변경해볼게요!
@@ -0,0 +1,18 @@
+export class LoadingHandler {
+  #loading;
+  constructor(initialValue) {
+    this.#loading = initialValue;
+  }
+
+  start() {
+    this.#loading = true;
+  }
+
+  end() {
+    this.#loading = false;
+  }
+
+  isLoading() {
+    return this.#loading;
+  }
+}

리뷰: 사용처를 보면, 로딩 상태 자체를 활용하는 경우가 한 번 밖에 없고,
start(), end() 실행과 함께 DOM 조작 로직이 함께 오는 것 같아요!

여기서 DOM 조작도 같이 해주고, 입력으로 조작할 요소를 같이 받으면 더 응집성이 높은 코드가 될 것 같아요!
@@ -0,0 +1,18 @@
+const DEFAULT_SEARCH_PARAMS = {
+  api_key: process.env.API_KEY,
+  language: 'ko-KR',
+};
+const MOVIE_BASE_URL = 'https://api.themoviedb.org/3/movie';
+
+export async function getPopularMovie(page) {
+  const param = new URLSearchParams({
+    ...DEFAULT_SEARCH_PARAMS,
+    page,
+  });
+
+  const response = await fetch(`${MOVIE_BASE_URL}/popular?${param}`);
+  if (response.ok) {
+    return response.json();
+  }
+  return { results: [] };
+}

리뷰: 여러개의 함수를 묶어서 내보내기 위함이다
-> 컨벤션만 맞다면 어떤 방향이던 상관 없다고 생각합니다!

다만, 저는 하나의 함수인 상황에서 함수가 더 추가되지 않았는데, 더 추가될 예정인데 이렇게 하신 것 같아서
남긴 코멘트이긴합니다!  (본문의 코멘트와 동일한 내용입니다 ㅎㅎ)
@@ -1,8 +1,43 @@
-import './Main.scss';
+import { useState, useEffect } from 'react';
+import Nav from '../../../components/Nav/Nav';
+import Feed from './Feed';
+import MainRight from './MainRight';
 import '../../../styles/variables.scss';
+import './Main.scss';
 
 function Main() {
-  return <></>;
+  const [articles, setArticles] = useState([]);
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/feedData.json')
+      .then(res => res.json())
+      .then(data => {
+        setArticles(data);
+      });
+  }, []);
+
+  return (
+    <div className="main">
+      <Nav />
+      <main>
+        <div className="feeds">
+          {articles.map((content, index) => {
+            return (
+              <div key={index}>
+                <Feed
+                  userName={content.userName}
+                  feedImg={content.feedImg}
+                  userMan={content.userMan}
+                  profileLogo={content.profileLogo}
+                />
+              </div>
+            );
+          })}
+        </div>
+        <MainRight />
+      </main>
+    </div>
+  );
 }
 
 export default Main;

리뷰: 컴포넌트 이름을 Feed 로 바꿔보면 좋을 것 같아요!!
이름에 의미를 더 담아주면 좋을 것 같습니다
@@ -1,8 +1,43 @@
-import './Main.scss';
+import { useState, useEffect } from 'react';
+import Nav from '../../../components/Nav/Nav';
+import Feed from './Feed';
+import MainRight from './MainRight';
 import '../../../styles/variables.scss';
+import './Main.scss';
 
 function Main() {
-  return <></>;
+  const [articles, setArticles] = useState([]);
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/feedData.json')
+      .then(res => res.json())
+      .then(data => {
+        setArticles(data);
+      });
+  }, []);
+
+  return (
+    <div className="main">
+      <Nav />
+      <main>
+        <div className="feeds">
+          {articles.map((content, index) => {
+            return (
+              <div key={index}>
+                <Feed
+                  userName={content.userName}
+                  feedImg={content.feedImg}
+                  userMan={content.userMan}
+                  profileLogo={content.profileLogo}
+                />
+              </div>
+            );
+          })}
+        </div>
+        <MainRight />
+      </main>
+    </div>
+  );
 }
 
 export default Main;

리뷰: mainRight도 컴포넌트로 만들어주면 좋을 것 같아요
이렇게 해주면 main.js 내용, scss 내용도 더 간단해질 것 같음!
```suggestion
        <MainRight />
```
@@ -1,8 +1,43 @@
-import './Main.scss';
+import { useState, useEffect } from 'react';
+import Nav from '../../../components/Nav/Nav';
+import Feed from './Feed';
+import MainRight from './MainRight';
 import '../../../styles/variables.scss';
+import './Main.scss';
 
 function Main() {
-  return <></>;
+  const [articles, setArticles] = useState([]);
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/feedData.json')
+      .then(res => res.json())
+      .then(data => {
+        setArticles(data);
+      });
+  }, []);
+
+  return (
+    <div className="main">
+      <Nav />
+      <main>
+        <div className="feeds">
+          {articles.map((content, index) => {
+            return (
+              <div key={index}>
+                <Feed
+                  userName={content.userName}
+                  feedImg={content.feedImg}
+                  userMan={content.userMan}
+                  profileLogo={content.profileLogo}
+                />
+              </div>
+            );
+          })}
+        </div>
+        <MainRight />
+      </main>
+    </div>
+  );
 }
 
 export default Main;

리뷰: ```suggestion
          <Footer />
```
컴포넌트로 분리해주고, footer 시멘틱 태그를 사용해보면 좋을 듯!
@@ -1,8 +1,43 @@
-import './Main.scss';
+import { useState, useEffect } from 'react';
+import Nav from '../../../components/Nav/Nav';
+import Feed from './Feed';
+import MainRight from './MainRight';
 import '../../../styles/variables.scss';
+import './Main.scss';
 
 function Main() {
-  return <></>;
+  const [articles, setArticles] = useState([]);
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/feedData.json')
+      .then(res => res.json())
+      .then(data => {
+        setArticles(data);
+      });
+  }, []);
+
+  return (
+    <div className="main">
+      <Nav />
+      <main>
+        <div className="feeds">
+          {articles.map((content, index) => {
+            return (
+              <div key={index}>
+                <Feed
+                  userName={content.userName}
+                  feedImg={content.feedImg}
+                  userMan={content.userMan}
+                  profileLogo={content.profileLogo}
+                />
+              </div>
+            );
+          })}
+        </div>
+        <MainRight />
+      </main>
+    </div>
+  );
 }
 
 export default Main;

리뷰: 각 메뉴를 JS 파일에 저장하고,
map 메소드로 출력해주는 방식으로 수정해보면 좋을 듯해용
@@ -0,0 +1,16 @@
+.main {
+  background-color: #fafafa;
+
+  main {
+    display: flex;
+    justify-content: center;
+    align-items: flex-start;
+    margin: 0px 8px 8px 8px;
+
+    .feeds {
+      width: 750px;
+      padding-top: 80px;
+      padding-bottom: 30px;
+    }
+  }
+}

리뷰: 이런 선택자 활용으로 스크롤 감추신 부분 좋네요..
@@ -1,8 +1,43 @@
-import './Main.scss';
+import { useState, useEffect } from 'react';
+import Nav from '../../../components/Nav/Nav';
+import Feed from './Feed';
+import MainRight from './MainRight';
 import '../../../styles/variables.scss';
+import './Main.scss';
 
 function Main() {
-  return <></>;
+  const [articles, setArticles] = useState([]);
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/feedData.json')
+      .then(res => res.json())
+      .then(data => {
+        setArticles(data);
+      });
+  }, []);
+
+  return (
+    <div className="main">
+      <Nav />
+      <main>
+        <div className="feeds">
+          {articles.map((content, index) => {
+            return (
+              <div key={index}>
+                <Feed
+                  userName={content.userName}
+                  feedImg={content.feedImg}
+                  userMan={content.userMan}
+                  profileLogo={content.profileLogo}
+                />
+              </div>
+            );
+          })}
+        </div>
+        <MainRight />
+      </main>
+    </div>
+  );
 }
 
 export default Main;

리뷰: feedcontainer 안 feed
@@ -1,7 +1,49 @@
 import './Nav.scss';
+import '../../styles/variables.scss';
+import { Link } from 'react-router-dom';
 
 function Nav() {
-  return <></>;
+  return (
+    <div className="nav">
+      <nav className="navbar">
+        <div className="navbarLeft1">
+          <div className="navbarLeft1Inner">
+            <Link to="/" className="navbarItem logoImg">
+              <img alt="logoIcon" className="navIcon" src="/images/logo.png" />
+            </Link>
+            <Link to="/" className="navbarItem logoFont">
+              Westagram
+            </Link>
+          </div>
+        </div>
+        <div className="navbarLeft2">
+          <div className="searchWrapper navbarItem">
+            <img alt="searchIcon" src="/images/search.png" />
+            <input placeholder="검색" />
+          </div>
+        </div>
+        <div className="navbarRight">
+          <Link to="/" className="navbarItem">
+            <img
+              alt="exploreIcon"
+              className="navIcon"
+              src="/images/explore.png"
+            />
+          </Link>
+          <Link to="/" className="navbarItem">
+            <img alt="heartIcon" className="navIcon" src="/images/heart.png" />
+          </Link>
+          <Link to="/" className="navbarItem">
+            <img
+              alt="profileIcon"
+              className="navIcon"
+              src="/images/profile.png"
+            />
+          </Link>
+        </div>
+      </nav>
+    </div>
+  );
 }
 
 export default Nav;

리뷰: 공통 파일
@@ -0,0 +1,14 @@
+import './Comment.scss';
+
+function Comment({ userName, content }) {
+  return (
+    <div className="comment">
+      <p>
+        <strong className="commentMan">{userName}</strong>
+        {content}
+      </p>
+    </div>
+  );
+}
+
+export default Comment;

리뷰: 매개변수 자리에서 구조분해할당 굳
@@ -0,0 +1,102 @@
+import { useState, useEffect } from 'react';
+import './Feed.scss';
+import Comment from './Comment';
+
+function Feed(props) {
+  const [comment, setComment] = useState('');
+  const [addCommentList, setAddCommentList] = useState([]);
+  const [cmtContList, setCmtContList] = useState([]);
+  const userName = 'test01';
+
+  const onChange = event => {
+    setComment(event.target.value);
+  };
+
+  const addComment = event => {
+    event.preventDefault();
+    setAddCommentList([
+      ...addCommentList,
+      {
+        name: userName,
+        content: comment,
+      },
+    ]);
+    setComment('');
+  };
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/commentData.json')
+      .then(res => res.json())
+      .then(data => {
+        setCmtContList(data);
+      });
+  }, []);
+
+  return (
+    <article className="feed">
+      <div className="feedTop">
+        <div className="feedTopOne">
+          <div className="profileLogo">
+            <img className="profileLogoImg" src={props.profileLogo} />
+          </div>
+          <div className="profileName">
+            <div className="profileNameOne">{props.userName}</div>
+            <span className="profileNameTwo">Wecode - 위코드</span>
+          </div>
+        </div>
+        <i className="fas fa-ellipsis-h" />
+      </div>
+      <img alt="피드 이미지" className="feedImg" src={props.feedImg} />
+      <div className="feedThree">
+        <div>
+          <i className="far fa-heart" />
+          <i className="far fa-comment" />
+          <i className="fas fa-upload" />
+        </div>
+        <i className="far fa-bookmark" />
+      </div>
+      <div className="feedFour">
+        <img alt="좋아요 누른 사람" className="man" src={props.userMan} />
+        <span className="feedFourWord">seungyoun_iain</span>
+        &nbsp;외&nbsp;
+        <span className="feedFourWordTwo">4명</span>이 좋아합니다.
+      </div>
+      <div className="feedFive">
+        <span className="feedFiveWord">wecode_bootcamp</span>"위코드는 단순
+        교육업체가 아닌 개발자 커뮤니티입니다. Wecode에서 배우고 저는 총 5개
+        회사에서 오퍼를 받았습니다.
+      </div>
+      <div className="comment">
+        {cmtContList.map(content => {
+          return (
+            <Comment
+              key={content.id}
+              userName={content.userName}
+              content={content.content}
+            />
+          );
+        })}
+        {addCommentList.map((content, index) => {
+          return (
+            <div key={index}>
+              <Comment content={content.content} userName={content.name} />
+            </div>
+          );
+        })}
+      </div>
+      <span className="postTime">54분 전</span>
+      <form className="commentSection" onSubmit={addComment}>
+        <input
+          type="text"
+          placeholder="댓글 달기..."
+          className="comment"
+          onChange={onChange}
+          value={comment}
+        />
+        <button className="postButton">게시</button>
+      </form>
+    </article>
+  );
+}
+
+export default Feed;

리뷰: - 재할당되지 않는 변수는 const로 선언하기
- 이 부분은 변수 선언보단 구조분해할당 적용하기
@@ -0,0 +1,102 @@
+import { useState, useEffect } from 'react';
+import './Feed.scss';
+import Comment from './Comment';
+
+function Feed(props) {
+  const [comment, setComment] = useState('');
+  const [addCommentList, setAddCommentList] = useState([]);
+  const [cmtContList, setCmtContList] = useState([]);
+  const userName = 'test01';
+
+  const onChange = event => {
+    setComment(event.target.value);
+  };
+
+  const addComment = event => {
+    event.preventDefault();
+    setAddCommentList([
+      ...addCommentList,
+      {
+        name: userName,
+        content: comment,
+      },
+    ]);
+    setComment('');
+  };
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/commentData.json')
+      .then(res => res.json())
+      .then(data => {
+        setCmtContList(data);
+      });
+  }, []);
+
+  return (
+    <article className="feed">
+      <div className="feedTop">
+        <div className="feedTopOne">
+          <div className="profileLogo">
+            <img className="profileLogoImg" src={props.profileLogo} />
+          </div>
+          <div className="profileName">
+            <div className="profileNameOne">{props.userName}</div>
+            <span className="profileNameTwo">Wecode - 위코드</span>
+          </div>
+        </div>
+        <i className="fas fa-ellipsis-h" />
+      </div>
+      <img alt="피드 이미지" className="feedImg" src={props.feedImg} />
+      <div className="feedThree">
+        <div>
+          <i className="far fa-heart" />
+          <i className="far fa-comment" />
+          <i className="fas fa-upload" />
+        </div>
+        <i className="far fa-bookmark" />
+      </div>
+      <div className="feedFour">
+        <img alt="좋아요 누른 사람" className="man" src={props.userMan} />
+        <span className="feedFourWord">seungyoun_iain</span>
+        &nbsp;외&nbsp;
+        <span className="feedFourWordTwo">4명</span>이 좋아합니다.
+      </div>
+      <div className="feedFive">
+        <span className="feedFiveWord">wecode_bootcamp</span>"위코드는 단순
+        교육업체가 아닌 개발자 커뮤니티입니다. Wecode에서 배우고 저는 총 5개
+        회사에서 오퍼를 받았습니다.
+      </div>
+      <div className="comment">
+        {cmtContList.map(content => {
+          return (
+            <Comment
+              key={content.id}
+              userName={content.userName}
+              content={content.content}
+            />
+          );
+        })}
+        {addCommentList.map((content, index) => {
+          return (
+            <div key={index}>
+              <Comment content={content.content} userName={content.name} />
+            </div>
+          );
+        })}
+      </div>
+      <span className="postTime">54분 전</span>
+      <form className="commentSection" onSubmit={addComment}>
+        <input
+          type="text"
+          placeholder="댓글 달기..."
+          className="comment"
+          onChange={onChange}
+          value={comment}
+        />
+        <button className="postButton">게시</button>
+      </form>
+    </article>
+  );
+}
+
+export default Feed;

리뷰: 함수명 수정!
- comment를 추가하는 역할을 하는 함수
- 엔터키를 쳤을 때 위 함수를 실행시키는 함수

로 분할하면 좋을 듯
@@ -0,0 +1,102 @@
+import { useState, useEffect } from 'react';
+import './Feed.scss';
+import Comment from './Comment';
+
+function Feed(props) {
+  const [comment, setComment] = useState('');
+  const [addCommentList, setAddCommentList] = useState([]);
+  const [cmtContList, setCmtContList] = useState([]);
+  const userName = 'test01';
+
+  const onChange = event => {
+    setComment(event.target.value);
+  };
+
+  const addComment = event => {
+    event.preventDefault();
+    setAddCommentList([
+      ...addCommentList,
+      {
+        name: userName,
+        content: comment,
+      },
+    ]);
+    setComment('');
+  };
+
+  useEffect(() => {
+    fetch('http://localhost:3000/data/younghyunHan/commentData.json')
+      .then(res => res.json())
+      .then(data => {
+        setCmtContList(data);
+      });
+  }, []);
+
+  return (
+    <article className="feed">
+      <div className="feedTop">
+        <div className="feedTopOne">
+          <div className="profileLogo">
+            <img className="profileLogoImg" src={props.profileLogo} />
+          </div>
+          <div className="profileName">
+            <div className="profileNameOne">{props.userName}</div>
+            <span className="profileNameTwo">Wecode - 위코드</span>
+          </div>
+        </div>
+        <i className="fas fa-ellipsis-h" />
+      </div>
+      <img alt="피드 이미지" className="feedImg" src={props.feedImg} />
+      <div className="feedThree">
+        <div>
+          <i className="far fa-heart" />
+          <i className="far fa-comment" />
+          <i className="fas fa-upload" />
+        </div>
+        <i className="far fa-bookmark" />
+      </div>
+      <div className="feedFour">
+        <img alt="좋아요 누른 사람" className="man" src={props.userMan} />
+        <span className="feedFourWord">seungyoun_iain</span>
+        &nbsp;외&nbsp;
+        <span className="feedFourWordTwo">4명</span>이 좋아합니다.
+      </div>
+      <div className="feedFive">
+        <span className="feedFiveWord">wecode_bootcamp</span>"위코드는 단순
+        교육업체가 아닌 개발자 커뮤니티입니다. Wecode에서 배우고 저는 총 5개
+        회사에서 오퍼를 받았습니다.
+      </div>
+      <div className="comment">
+        {cmtContList.map(content => {
+          return (
+            <Comment
+              key={content.id}
+              userName={content.userName}
+              content={content.content}
+            />
+          );
+        })}
+        {addCommentList.map((content, index) => {
+          return (
+            <div key={index}>
+              <Comment content={content.content} userName={content.name} />
+            </div>
+          );
+        })}
+      </div>
+      <span className="postTime">54분 전</span>
+      <form className="commentSection" onSubmit={addComment}>
+        <input
+          type="text"
+          placeholder="댓글 달기..."
+          className="comment"
+          onChange={onChange}
+          value={comment}
+        />
+        <button className="postButton">게시</button>
+      </form>
+    </article>
+  );
+}
+
+export default Feed;

리뷰: 동일한 스타일을 가지는 부분인데, one two three 이런 식으로 나타낼 필요 없이 내용을 포괄하는 명칭의 동일한 className으로 사용
@@ -0,0 +1,132 @@
+.feed {
+  background-color: white;
+  margin-bottom: 50px;
+
+  .feedTop {
+    display: flex;
+    justify-content: space-between;
+    position: relative;
+    padding: 10px;
+
+    .feedTopOne {
+      display: flex;
+      align-items: center;
+
+      .profileLogo {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        height: 35px;
+        width: 35px;
+        margin-right: 10px;
+        color: white;
+        background-color: black;
+        border-radius: 50%;
+        font-size: 7px;
+        font-weight: bold;
+        overflow: hidden; // 부모 div만큼 이미지 자름
+
+        .profileLogoImg {
+          width: 100%;
+          height: 100%;
+          object-fit: cover; // 가로, 세로 비율이 안 맞으면 딱 맞게 안 찌그러지게 맞춰줌.
+        }
+      }
+
+      .profileNameOne {
+        margin-bottom: 0px;
+        font-size: 15px;
+        font-weight: bold;
+      }
+
+      .profileNameTwo {
+        color: #a3a49a;
+        font-size: 12px;
+        font-weight: bold;
+      }
+    }
+
+    .fa-ellipsis-h {
+      position: absolute;
+      right: 20px;
+      top: 20px;
+    }
+  }
+
+  .feedImg {
+    width: 100%;
+    height: 500px;
+  }
+
+  .feedThree {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px;
+    font-size: 25px;
+
+    .fa-heart,
+    .fa-comment {
+      margin-right: 10px;
+    }
+  }
+
+  .feedFour {
+    display: flex;
+    align-items: center;
+    padding: 0px 10px 10px 10px;
+
+    .man {
+      width: 20px;
+      height: 20px;
+      margin-right: 10px;
+      border-radius: 50%;
+    } // 위 코드 처럼 하려면 div로 이미지 한번 더 감써서 그 div에 overflow:hidden 주고
+    // img파일에 width: 100%, height: 100%, object-fit: cover주면 됨
+
+    .feedFourWord,
+    .feedFourWordTwo {
+      font-weight: bold;
+    }
+  }
+
+  .feedFive {
+    padding: 0px 10px 3px 10px;
+
+    .feedFiveWord {
+      font-weight: bold;
+    }
+  }
+
+  .comment {
+    padding-top: 5px;
+    padding-left: 5px;
+    padding-bottom: 5px;
+  }
+
+  .postTime {
+    display: inline-block;
+    padding: 10px 10px 15px 10px;
+    color: #9c9c9c;
+  }
+
+  .commentSection {
+    position: relative;
+
+    .comment {
+      width: 100%;
+      padding: 15px 10px;
+      border: 1px solid #f3f3f3;
+    }
+
+    .postButton {
+      position: absolute;
+      bottom: 13px;
+      right: 20px;
+      color: #c5e1fc;
+      background-color: white;
+      border: 1px solid white;
+      font-size: 15px;
+    }
+  }
+}

리뷰: - article 태그가 아니라 feed라는 className으로 nesting하기
- 최상위 div를 article로 바꾸고 1 depth 줄이면 될 듯