// App.js
function App() {
  const Login = lazy(() => import('./page/Login'));
  const LogOut = lazy(() => import('./page/LogOut'));
  const SignPage = lazy(() => import('./page/SignPage/SignPgae'));
  const Questions = lazy(() => import('./page/Questions'));
  const CreateQuestionPage = lazy(() => import('./page/CreateQuestionPage'));
  const Post = lazy(() => import('./components/Post/Post'));
  const AnswerEdit = lazy(() => import('./page/AnswerEdit'));
  //const User = lazy(() => import('./page/User'));
  const Tags = lazy(() => import('./page/Tags'));
  const User = lazy(() => import('./page/User'));

  const [datas, setDatas] = useState(dummyData);

return (
    <Router>
      <GlobalStyles />
      <Main>
        <Suspense fallback={<div>Loading...</div>}>
          <Routes>
			// ... 생략
            <Route
              path="/questions/:id"
              element={<Post datas={datas} setDatas={setDatas} />}
            />
            // ... 생략

dummyData에서 데이터를 datas 배열로 가져와서 Post 로 보내줬다.

그리고 Post에서 꺼내와서 {} 로 값을 동적으로 주면 되는데 datas 에서 어떻게 꺼내야 할 지 감을 전혀 못잡고 있었다

 

 

//dummyData.js

const dummyData = [
  {
    id: 1,
    title: '게시글 제목',
    likes: 0,
    answers: 0,
    views: 2,
    body: `I am building a large project on a remote machine using Bazel. Clean build times are around 30 minutes. Incremental builds (changing code in 1-2 files) typically take around 10-20 seconds.

    The problem I have is that when I log out of my machine and log back in again after 1-2 days the build command takes around 10 minutes even though I have not modified any source code.
    
    If I call bazel shutdown and then call bazel build again the "no-build" op takes around 5-10 seconds (i.e. much better than the other "no-build" op).
    
    If I log out and log back in again immediately I can see there is still a bazel process running in the background, which disappears when I call bazel shutdown. I am guessing that when I do not shut bazel down properly it gets killed in such a way that corrupts or deletes cached data. The long "no-build" op then spends a long time reconstructing data that was previously stored in the Bazel cache.
    
    Is there a way to automatically shut down the bazel server when I am disconnected? Preferably this should work both when (i) I call exit from the command-line to log out, (ii) I get automatically disconnected through some kind of timeout or interruption in network connectivity.`,
    tag: ['java', 'c++'],
    user: {
      username: 'Heera',
      createdAt: 'asked 46 secs ago',
    },
  },
  {
    id: 2,
    title: '2번째 글',
    likes: 2,
    answers: 10,
    views: 56,
    body: '2번재 오랜만에 글을 작성해 보는데 말이죠... 이거는 정말,.. 제가 할 수 있는 일인가에 대한걸 다시 고민해봐야 할 시점인것 같습니다만.. 얼마나 길게 쓴게 잘려서 나올지 한번 테스트 해보도록 하겠습니다.. 이정도면 엄청 길게 쓴게 아닐까요?? 정말 고민이 많이 됩니다.. 이게 한꺼번에 다 나오지 않아야 할텐데 말이죠... 조금만 더 길게 적어보겠습니다.조금만 더 길게 적어보겠습니다.조금만 더 길게 적어보겠습니다. 이정도면 될거같은데, 사이즈가 늘어나 버려서 더 길게 작성하고, 크기 가 넘어가는 내용은 안나오는지 확인해 보려고 합니다~',
    tag: ['java', 'javascript', 'python'],
    user: {
      username: 'seoyeon',
      createdAt: 'asked 46 secs ago',
    },
  },
  {
    id: 3,
    title: '세번째 글입니다만...',
    likes: 34,
    answers: 668,
    views: 23234,
    body: '안녕하세요 제 질문은요/..',
    tag: ['java', 'logic', 'nameerror', 'firebase-authentication'],
    user: {
      username: 'kim.s.y',
      createdAt: 'asked 5 mins ago',
    },
  },
  {
    id: 4,
    title: '4번째 글',
    likes: 2,
    answers: 8,
    views: 45,
    body: '444444 내용이랄게 없지만서도 적으면 또 적을수도 있는데,.. 데체 긴 내용은 어떻게 길이를 줄일까요',
    tag: ['java', 'c++'],
    user: {
      username: 'harnry',
      createdAt: 'asked 7 mins ago',
    },
  },
 //... 생략
 ]

export default dummyData;

더미 데이터는 배열 안에 객체가 들어가있는 형태.

객체다 보니까 인덱스 값이 없었다.

 

const { id } = useParams();

를 사용해 console.log({id})를 찍어보면 url의 id 값이 잘 찍혔다.

{ id }과 datas의 id 값이 같은 걸 찾아서 post에 뿌려주면 될 거 같다는 윤곽이 잡혔다.

 

그런데 datas.id 가 계속 null 혹은 undefined가 나왔다 (객체니까....)

여기서부터 6시간 이상을 별 시도를 다 해봤다.

이것저것 찾다가 아래의 글을 보고 아이디어를 얻었다.

 

https://velog.io/@lilyoh/js-object-%EC%9A%94%EC%86%8C%EC%97%90-%EC%A0%91%EA%B7%BC%ED%95%98%EA%B3%A0-%EC%88%9C%ED%9A%8C%ED%95%98%EA%B8%B0

 

[js] object 요소에 접근하고 순회하기

info 객체에 키를 생성하고 값을 할당해주려고 한다. 키와 값은 변수를 통해 받아온다.위와 같은 변수가 주어졌을 때, info 객체에 키와 값을 할당하는 방법은 2 가지가 있다.객체의 요소는 인덱스(

velog.io

 

for in 문으로 객체를 순회해서 datas[i].id 를 구하고 그것을   { id } 와 비교하자!

개발자도구에 바로 시도를 해봤다.

 

잘 뜬다!

이걸로 시도를 해봤다

 

시도한 코드

=> 문제점

  • if문이 제대로 작동을 안함
    • {id} ==! datas[i].id 가 false 인게 맞다면 error 가 떠야하는데 <Container> 가 화면에 뜸
  • {id} 를 콘솔에 수십번을 찍어봤는데도 문자열이라는 걸 눈치못챔
  • {id} 는 url의 `.../:id` 에 맞게 변하는데 datas[i].id 는 1에서 변하질 않음
    • 그래서인지 질문리스트에서 다른 제목을 눌러봐도 {id}만 제대로 바뀌고, 안에 Post 내용들은 1번째 글이랑 똑같이 뜸...
const Post = () => {
  const { id } = useParams();
  const [datas, setDatas] = useState(dummyData);

  for(let i in datas){
    if({id} ==! datas[i].id){
      return(
        <div>result error</div>
      )
    }
    console.log(`data[i].id`, datas[i], datas[i].id, {id})
    return(
      <>
      <div>
        <Container>
          <Nav />
          <Content>
            <div className="div-css">
              <div>
                <PostTitle datas={datas[i]} setDatas={setDatas} />
              </div>
              <div className="div-inline-block">
                <div className="div-flex">
                  <Like />
                  <PostMainText datas={datas[i]} />
                  <PostAside>
                    <div>aside</div>
                  </PostAside>
                </div>
              </div>
              <Answers />
            </div>
          </Content>
        </Container>
        <Footer />
      </div>
    </>
    );
  }
}

 

구글링으론 원하는 결과가 안 나와서 유튜브에 검색했다.

검색어 : js useParams

그러다가 아래의 영상을 보게 되었다.

 

https://youtu.be/vI-XtN_Zdfg

 

유레카!!

아무 기대없이 봤는데 내 상황에 써먹을 수 있겠다는 생각이 들어 침대에서 벌떡 일어나 다시 노트북을 켰다

 

 

수정한 코드

=> 문제점

  • .map() 을 사용해 data.id와 {id} 가 같은 데이터를 Post에 뿌려주기 때문에 id가 같으면 post가 똑같은 내용이 두번 뜸
    • 하지만 ID는 고유값이기 때문에 괜찮음 ㅎ
  • Answers 컴포넌트도 .map() 안에 넣어야 함.
    • Answers의 답변 내용들도 질문마다 다르기 때문에 넣어야함 근데 넣으면 레이아웃 잡아둔 거 난리날까봐 내일수정하기로 함
const Post = () => {
  const { id } = useParams();
  const [datas, setDatas] = useState(dummyData);
  const datasSame = datas.filter((data) => data.id === Number(id));

  console.log(`dataSame`, datasSame);
  return (
    <>
      <div>
        <Container>
          <Nav />
          <Content>
            <div className="div-css">
              <div className="예시">
                {datasSame.map((data) => (
                  <>
                    <div key={data.id}>
                      <div>
                        <PostTitle datas={data} setDatas={setDatas} />
                      </div>
                      <div className="div-inline-block">
                        <div className="div-flex">
                          <Like />
                          <PostMainText datas={data} />
                          <PostAside>
                            <div>aside</div>
                          </PostAside>
                        </div>
                      </div>
                    </div>
                  </>
                ))}
              </div>
              <Answers />
            </div>
          </Content>
        </Container>
        <Footer />
      </div>
    </>
  );
};

콘솔에도 잘 뜬다

 

=> 추가 (22.11.08)

map 과 필터를 지워져도 정상적으로 구동되게 코드를 아래와 같이 변경하였다.

기존과는 다르게 app.js 데이터를 props 로 내려주지 않고, Post.js 에서 fetch 로 데이터를 바로 받아오면서 수정하게 된 코드이다.

const Post = ({ qid, setQid,setAid, setAnswerEditContent }) => {
  const { id } = useParams();
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetch(
      `url주소/${id}`,
      { method: 'GET' },
    )
      .then((response) => response.json())
      .then((post) => {
        setPosts(post.data);
        setQid(id);
      });
  }, [id]);
  return (
    <>
      <div>
        <Container>
          <Nav />
          <Content>
            <div className="div-css">
              <div className="예시">
                    <div key={posts.questionId} className="div-css">
                      <div>
                        <PostTitle datas={posts} key={id} />
                      </div>
                      <div className="div-inline-block">
                        <div className="div-flex">
                          <div className="div-inline-flex">
                            <div className="div-inline-block">
                              <div className="div-flex">
                              <Like datas={posts} />
                              <PostMainText datas={posts} />
                              </div>
                              <Answers answers={posts.answers} qid={qid} setAid={setAid} setAnswerEditContent={setAnswerEditContent}/>
                            </div>
                          </div>
                          //...생략

버튼이 죽어도 오른쪽 정렬이 안됨

=> 각 요소를 양쪽 정렬 시켜서 해결

display: flex;
    justify-content: space-between;

 

ask 버튼을 <link> 안에 넣으니 Margin-left:auto 가 안 먹힘

=> Link 태그에 CSS 로 Margin-left:auto 주니 해결 완료

**** 원래 작업하던 폴더, 파일들 복사해서 잘 모셔두기!

 

  • 원격 레포에서 git clone 으로 새롭게 폴더를 가져온다 (ㅋㅋ...
  • git remote -v 로 원격 레포랑 연결 잘 되어있는 지 확인한다
  • 새로운 브런치를 파고 거기로 이동한다
    • git checkout -b <새로운브런치이름>

 

  • git pull (remote) dev-fe 로 pull 해온다
    • remote는 origin 일 수도 pre015일 수도 있음 2번에 확인 했을 때 뜨는 걸로

 

  • pull 후 병합과 오류를 수정한다...
  • 자신이 작성했던 파일, 폴더들을 git clone 으로 새로판 폴더에 다시 작성한다
  • 오류가 없는 걸 확인했다면      git push <remote> <아까 만들었던 새로운 브런치 이름>      한다! 

 

  • giithub 으로 가서 pr을 날린다

 

 


 

 

이렇게 했는데도 이상한 commit 들이 끼어있긴 하더라...

다음에 pull 해올 때 아래 같은 게 또 뜨면

 

git config pull.rebase false 가 아니라    (항상 얘로 했었음....)

git config pull.ff only 로 해 보던가 해야겠다.

 * branch            dev-fe     -> FETCH_HEAD
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint: 
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint: 
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.

 

 

 

 

**** 11/07 수정 ****

 

내가 작업한 거 pr 보내고, 머지하고 -> 아무것도 안하다가 -> 다른 분이 머지하신 거 받아올 때 git clone 부터 다시 해왔다 ㅋㅋㅋㅋ....

 

내거 머지하고 코드 작업 했으면

1) git clone 으로 새로 하나 파자

2) main 브랜치로 되어있으니까 브랜치 새로 파서

3) 거기서 pull 하고

4) 작업했던 코드들 넣는 식으로 하자...

 

 

Consider adding an error boundary to your tree to customize error handling behavior.

=>

 

styled-component 로 작성한 button 컴포넌트에 class가 적용되지 않는 에러

=> .sign 앞에 & (자기 자신)을 붙여줘서 해결 완료

export const ButtonStyled = styled.button`
  border: solid 1px #2d8de0;
  background-color: #e8f2fa;
  border-radius: 3px;
  width: 60px;
  margin: 3px;
  padding: 5px 0 5px 0;
  text-align: center;
  color: #2273ba;
  font-size: 0.8rem;

  &:hover {
    background: #d5e4f0;
  }

  &.sign {
    background-color: #2d8de0;
    color: #ffffff;
  }

  &.sign:hover {
    background-color: #2273ba;
  }
`;

 

Uncaught Error: input is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.

=> 자식을 가질 수 없는 (input)태그에 자식을 넣어서 생기는 오류이다.

const SearchInput = () => {
  const [value, setValue] = useState('');
  const handleChange = (e) => {
    setValue(e.target.value);
    alert('input 값 입력중');
  };
  return (
    <>
      <input
        type="text"
        value={value}
        onChange={handleChange}
        placeholder="Search..."
       >
       <SearchGuide> //이 부분을 삭제하여 해결 가능
      </input>
    </>
  );
};

 

 

Uncaught Error: Expected `onClick` listener to be a function, instead got a value of `object` type.

=> 자식 컴포넌트가 props으로 함수를 받았는데 그걸 이벤트함수에 그냥 받을 경우 발생하는 오류

//X
<input
          type="text"
          value={value}
          onChange={handleChange}
          onClick={
            isSearchHandler ? <SearchGuide /> : '되는 거 맞냐고'
          }
          placeholder="Search..."
/>
// O
<input
          type="text"
          value={value}
          onChange={handleChange}
          onClick={() =>
            isSearchHandler() ? <SearchGuide /> : '되는 거 맞냐고'
          }
          placeholder="Search..."
/>

 

 

<magnifyingGlass /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.

=> 스타일드 컴포넌트인데 컴포넌트명이 소문자로 시작해서 생긴 오류. m을 대문자로 바꿔주면 해결 가능.

 

 

 

Uncaught ReferenceError: Cannot access 'ButtonStyled' before initialization

=> ButtonStyled 스타일드 컴포넌트는 Header.js에서 만들었고,

그걸 SearchBar.js 로 import 해 가져가 사용하는 중이었는데

아래 코드에서 보다시피 ButtonStyled 보다 SearchBar 컴포넌트가 먼저 불러와져서 생긴 오류였다.

 

해결방법 : ButtonStyled를 Header.js 에서 만들어서  SearchBar.js 에서도 사용하는 게 아니라

SearchBar.js에서 만들어서 Header.js 에서도 사용하는 걸로 변경했다.

return (
      <>
        <GuestsStyled>
          <ProductsStyled>About</ProductsStyled>
          <ProductsStyled>Products</ProductsStyled>
          <ProductsStyled>For Teams</ProductsStyled>
          <SearchBar />
          <ButtonStyled>Log in</ButtonStyled>
          <ButtonStyled className="sign">Sign up</ButtonStyled>
        </GuestsStyled>
      </>
    );
  }

 

 

Using exported name 'UserProfileStyled' as identifier for default export.

=> Header 컴포넌트에 들어가는 UserProfileStyled 컴포넌트를 Post 컴포넌트에서도 import 해서 가져와 사용하려고 하니까 이런 에러가 떴다. 해결 방법은 UserProfileStyled 를 중괄호 안에 넣어주면 된다.

import UserProfileStyled from '../components/Header/UserProfile';  //X
import { UserProfileStyled } from '../components/Header/UserProfile'; //O

 

 

onClick 이벤트를 사용해 아이콘 클릭시 div 박스 class hide(기본값)에 show가 추가되게끔 구현하는 것이 안 됨.

=> 콘솔에도 오류가 뜨지 않아 대체 뭐가 문제인지 고민했다.

serchBar 부분에 똑같은 식으로 적용했을 땐 문제가 없었는데...

고민을 하다보니 컴포넌트 안에 하위 컴포넌트에 식을 적용한 게 문제였다.

//안 됐을 때
<UserIconStyled>
        <MdMessage className="userIcon" onClick={isIconHandler} />
</UserIconStyled>
<LogOutBox>
        <InBox className={`hide ${isIconClick ? 'show' : null}`} />
</LogOutBox>

//수정 후 잘 작동함
<UserIconStyled onClick={isIconHandler}>
        <MdMessage className="userIcon" />
</UserIconStyled>
<LogOutBox className={`hide ${isIconClick ? 'show' : null}`}>
        <InBox />
</LogOutBox>

 

prettier 오류

npm install --save-dev prettier

npm install --save-dev prettie --legacy-peer-deps

=> 위에 거 둘 다 해봤는데 아래처럼 오류가 뜨고 안 되길래 npm install --save-dev prettier --force 로 해봤더니 오류 해결

npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: @toast-ui/react-editor@3.2.2
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR!   peerOptional react@"^16.9.0 || ^17.0.0 || ^18" from @reduxjs/toolkit@1.8.6
npm ERR!   node_modules/@reduxjs/toolkit
npm ERR!     @reduxjs/toolkit@"^1.8.6" from the root project
npm ERR!   peer react@"^18.0.0" from @testing-library/react@13.4.0
npm ERR!   node_modules/@testing-library/react
npm ERR!     @testing-library/react@"^13.4.0" from the root project
npm ERR!   10 more (react-dom, react-icons, react-moment, react-redux, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.1" from @toast-ui/react-editor@3.2.2
npm ERR! node_modules/@toast-ui/react-editor
npm ERR!   @toast-ui/react-editor@"^3.2.2" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: react@17.0.2
npm ERR! node_modules/react
npm ERR!   peer react@"^17.0.1" from @toast-ui/react-editor@3.2.2
npm ERR!   node_modules/@toast-ui/react-editor
npm ERR!     @toast-ui/react-editor@"^3.2.2" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/heeraan/.npm/eresolve-report.txt for a full report.

 

 

'/Users/heeraan/Desktop/project/plz/seb40_pre_015/client/node_modules/react/index.js' imported multiple times.
=> react 에서 import 해오는 게 여러개인데 한 꺼번에 Import 한 게 아니라 여러개로 import 해와서 생긴 오류
// X
import { Suspense, lazy } from 'react';
import { useState } from 'react';

//O
import { Suspense, lazy, useState } from 'react';

 

 

 

 


 

 

 

백엔드 서버에서 질문 데이터를 아래처럼 받아와서 사용을 하려고 하니까 질문 리스트가 화면에 뜨질 않는 문제 해결

더보기

백엔드 서버에서 질문 데이터를 아래처럼 받아와서 사용을 하려고 하니까 질문 리스트가 화면에 뜨질 않았다...

  const [datas, setDatas] = useState([]);
  console.log(datas);

  useEffect(() => {
    fetch(
      '환경변수/questions'
    )
      .then((response) => response.json())
      .then((data) => {
        setDatas(data);
      });
  }, []);
  console.log(`questions`, datas);
  
  
  <Route path="/" element={<Questions datas={data} />} />

 

응답을 보면 응답이 data안에 들어있다. 그래서 아래처럼 한커풀 벗겨서 넘겨줘야 한다.

그리고 환경변수를 사용하니 안 된 거였다. (대체 왜...)

<Route path="/" element={<Questions datas={datas.data} />} />

 

 

 

 

서버에서 데이터를 받아와 질문 리스트를 띄우는 것엔 성공했으나, 질문 리스트의 제목을 클릭 했을 때 Post.js 가 제대로 뜨지 않는 문제 발생

더보기

 

App.js 에서 fetch 받아온 질문 리스트 데이터들을 <Post /> 컴포넌트에 datas 로 내려줌

//App.js

useEffect(() => {
    fetch(
      'http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions'
    )
      .then((response) => response.json())
      .then((data) => {
        setDatas(data);
      });
  }, []); //여기에 data 넣으면 지옥 경헙 삽가능... -지은
  console.log(`questions`, datas);
  
  
  	<Route path="/" element={<Questions datas={datas.data} />} />
	<Route
		path="/questions"
		element={<Questions datas={datas.data} />}
	 />
 	<Route
        path="/questions/:id"
        element={<Post datas={datas.data} />}
   	/>

 Post.js 데이터 받아오는 것을 어느 정도 수정하고 팀원이 dev-fe 브랜치에 머지해 놓은 것을 pull 해왔더니 갑자기 브라우저창이 계속 새로고침 되는 문제가 발생했다! 데이터 잘 들어오나 확인하려고 console.log 를 찍어놓은 것도 많아서 콘솔창이 미친듯이 밑으로 내려가고 ... 화면은 계속 렌더링 되느라 깜빡거리고... 새벽 4시에 컴퓨터 귀신 들린 줄 알고 놀랐다 (...)

문제는 useEffect 두번째 인자로 [] 배열 안에 data를 넣어서였다. 내가 넣은 건 아니였는데 배열안에 data를 넣어서 data가 들어올 때마다 새로 렌더링 되면서 생긴 문제인 거 같다.

 

 

아무튼 datas 를 받아온 Post.js 에 아래와 같이 적어줬다.

const Post = ({ datas }) => {
  const { id } = useParams();
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetch(
      `http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions?id=${id}`,
      { method: 'GET' }
    )
      .then((response) => response.json())
      .then((post) => {
        setPosts(post.data);
      });
  }, [id]);
  console.log(`id`, {id})
  console.log(`post에 데이터 잘 들어옴?`, posts)

  const idSame = posts?.filter((postId) => postId.questionId === Number(id));
  //{id}를 숫자로 바꾸고 datas의 id 비교. -> 같은 것만 idSame

 

 

이렇게 코드를 짰더니

 

 

 

질문 리스트에서 타이틀을 누르면

 

 

이렇게 뜨는 거다...

url 의 params {id} 는 잘 들어와서 찍히는데... {id} 가 질문 리스트 클릭한 타이틀의 id 로 들어오지 않는 것이다...

{id} 는 제대로 찍히고 있는 걸 보고 url 창에서 직접 질문의 id 를 적어봤다

 

 

이렇게 했더니 잘 뜨는 것이다...!

대체 뭐가 문제인가 이것도 해 보고 저것도 해 보고 했는데...

서버쪽 응답 data의 id가 id 가 아니라 questionId인데

 

Question.js (질문 리스트)에서 타이틀을 클릭했을 때 Link의 to의 url이 잘못 적혀있던 것이었다.

//X
<Link to={`/questions/${id}`}>
   <h3>{title}</h3>
</Link>

<Link to={`/questions/:id`}>
   <h3>{title}</h3>
</Link>


//O
<Link to={`/questions/${questionId}`}>
   <h3>{title}</h3>
</Link>

id 와 {id} 와 questionId... 정말 헷갈린다...@.@

위의 질문 리스트에서 타이틀을 클릭했을 때 안 됐던 것은 {title}을 감싸고 있는 Link 의 문제였고, url에 직접 params를 입력했을 때 data가 잘 뜨던 것은 Post.js 에서 id 를 useParams로 받아오기 때문이었던 거 같다.

const Post = () => {
  const { id } = useParams(); //<<<- 이부분
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetch(
      `http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions?id=${id}`,
      { method: 'GET' },
    )
      .then((response) => response.json())
      .then((post) => {
        setPosts(post.data);
      });
  }, [id]);

 

+ 추가 

Post.js의 패치를 위처럼 /questions?id=${id} 로 보내면 네트워크에 ${id} 만 보내지는 게 아니라 ( ex: 19) id=19 로 보내져서 혼동이 생길 수 있다고 한다. (정확한 단어가 있었는데 자세히 기억이 안남)

그래서 원래 적었던 것처럼 /questions/${id} 로 적는 게 맞고, 대신 이렇게 적었을 때 화면에 뜨지 않던 오류는 아래처럼 해결하면 된다. (filter 삭제, map 삭제)

 

map 으로 data 를 뿌려줘야 한다고 생각하고 있었는데 완전 잘못된 생각이었다.

왜냐면... 게시글 리스트가 아니라 게시글 1개만 보여지는 화면이니까...! 복잡하게 생각할 것이 많아서 잘못 생각하고 있었다.

//O
const Post = () => {
  const { id } = useParams();
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetch(
      `http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions/${id}`,
      { method: 'GET' },
    )
      .then((response) => response.json())
      .then((post) => {
        setPosts(post.data);
      });
  }, [id]);
//X
const idSame = posts?.filter((postId) => postId.questionId === Number(id));
  return (
    <>
      <div>
        <Container>
          <Nav />
          <Content>
            <div className="div-css">
              <div className="예시">
                {idSame?.map((posts) => (
                  <>
                    <div key={posts.id} className="div-css">
                      <div>
                        <PostTitle datas={posts}/>
                      </div>
                      <div className="div-inline-block">
                        <div className="div-flex">
                          <div className="div-inline-flex">
                            <div className="div-inline-block">
                              <div className="div-flex">
                              <Like datas={posts} />
                              <PostMainText datas={posts} />
                              </div>
                              <Answers answers={posts.answer} />
                            </div>
                          </div>
                          
                          ... 생략
  
 //O
  return (
    <>
      <div>
        <Container>
          <Nav />
          <Content>
            <div className="div-css">
              <div className="예시">
                    <div key={posts.id} className="div-css">
                      <div>
                        <PostTitle datas={posts}/>
                      </div>
                      <div className="div-inline-block">
                        <div className="div-flex">
                          <div className="div-inline-flex">
                            <div className="div-inline-block">
                              <div className="div-flex">
                              <Like datas={posts} />
                              <PostMainText datas={posts} />
                              </div>
                              <Answers answers={posts.answer} />
                            </div>
                          </div>
                          
                          ... 생략

 

 

게시글 삭제 기능 구현하기

더보기

CRUD CRUD 노래를 불렀는데...

delete 기능 구현을 모두 깜빡하고 있었다

마감 하루를 남기고 구현 시작...!

 

PostFooter.js 에 <p>Delete</p> 를 만들어주고 css 로 커서 포인터를 주고, onClick 함수를 만들어줬다.

onClick 함수엔 fetch 가 들어갈 것이다.

<p onClick={PostDelete} className="delete-margin">Delete</p>

.delete-margin {
    margin-left: 10px;
    cursor: pointer;
  }

 

onClick 함수로 사용할 PostDelete 이다. 딜리트 구현은 생각보다 어렵지 않았다.

그런데 응답에서 status 를 받아오는 것과 navigater 사용이 미숙해서 거기서 실수가 있었다.

 

우선

이것저것 찾아보면서 .then((res) => res.text) 로 응답 메세지를 받아와서 OK 면 alret 창을 띄우는 if문을 구현했는데 서버에서 보내주는 응답에 body가 없었다... (두둥) status 코드 204 를 받아와 저 부분을 해결해야했다.

 

204를 받아오는데 alert 이 삭제 완료가 뜨는 게 아니라 계속 삭제 실패가 떴다. (근데 게시글 데이터 삭제는 잘 되고 있었다)

//X
const PostDelete = () => {
    fetch(`http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions/${questionId}`, {
      method: "DELETE",
    })
    .then(response => {
      if (response.status === '204'){
        console.log(response.status);
        alert('삭제 완료')
        navigator('/')
      }
    })
    .catch((error) => {
      alert('삭제 실패')
    })
  }


//O
import { useNavigate } from 'react-router-dom';
const PostFooter = ({ datas }) => {
  const { questionId, title, likes, answers, views, body, tag } = datas;
  const navigator = useNavigate();
    const PostDelete = () => {
        fetch(`http://ec2-3-34-90-191.ap-northeast-2.compute.amazonaws.com:8080/questions/${questionId}`, {
          method: "DELETE",
        })
        .then(response => {
          if (response.status === 204){
            console.log(response.status);
            alert('삭제 완료')
            navigator('/')
            window.location.reload()
          }
        })
        .catch((error) => {
          alert('삭제 실패')
        })
      }

문제1) 상태 코드 204를 숫자가 아닌 문자열로 if문에 적었다...!

해결 =>  if(response.status ===  '204') 가 아니라 if(response.status === 204) 로 적었어야 했다...

 

 

문제2) navigator('/') 이 작동하지 않음

해결 => react-router-dom 에서  { useNevigate } 를 import 해와야 한다. 그리고 fetch 가 들어간 함수 밖에서 navigator 로 선언을 해줘야 제대로 쓸 수 있었다!

 

 

문제3) 리다이렉션 구현...

해결 => 리다이렉션을 어떻게 써야할지 모르겠어서 팀원분께 여쭤보니 window.location.reload() 를 알려주셨다. 넣으니까 게시글 삭제 후 게시글 리스트 페이지로 잘 이동됐다!

 

 

 

 

로그인 여부에 따라 헤더 다르게 보이기 구현

더보기

이것저것 찾아보면서 코드를 짰더니 짬뽕이 되서 얘가 이상하게 작동을 했다.

 

기본적으로 const [ isLogin, setIsLogin ] = useStates(false) 이다.

그렇다면 !isLogin 이면 true 니까 login이 된 상태니까 아래쪽 리턴문을 띄워야하는데 얘가 로그인이 안 된 상태를 보여주는 윗쪽 리턴문을 띄웠다...

 

이건 내가 수정을 한 것은 아니지만 로그인을 구현하신 팀원분께서 리턴문 두개가 아니라 삼항연산자를 사용해야 한다고 알려주셨다.

const Guest = (isLogin) => {
  if (!isLogin) {
    console.log(`Header is isLogin`, isLogin);
    return (
      <>
        <GuestsStyled>
          <ProductsStyled>About</ProductsStyled>
          <ProductsStyled>Products</ProductsStyled>
          <ProductsStyled>For Teams</ProductsStyled>
          <SearchBar />
          <Link to="/login">
            <ButtonStyled>Log in</ButtonStyled>
          </Link>
          <Link to="/signup">
            <ButtonStyled className="sign">Sign up</ButtonStyled>
          </Link>
        </GuestsStyled>
      </>
    );
  }
  return (
    <>
      <UserStyled>
        <ProductsStyled>Products</ProductsStyled>
        <SearchBar />
        <UserHeader />
      </UserStyled>
    </>
  );
};

+ Recent posts