Codestates/Pre-project

[pre-poject] error 목록

Tite 2022. 10. 25. 23:31

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>
    </>
  );
};