인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

stefan CHO님의 프로필 이미지
stefan CHO

작성한 질문수

React로 NodeBird SNS 만들기

post를 작성하고 form 을 제출할때마다 페이지가 새로고침이 됩니다..

해결된 질문

작성

·

1.1K

0

제로초님 어제오늘 해보고 있는데, 코드 비교해도 문제점을 잘모르겠고 시간이 너무 지체되는것 같아서

질문드립니다..

코드는 깃헙에 올렸습니다. 혹시 봐주실 수 있을까요? 현재 6-3까지 학습한 상태입니다.

(모두 ch1 안에 있습니다.)

https://github.com/stefan-CHO/react-sns-tweeter

현상 :

form을 제출시에(post를 만들면) 페이지가 새로고침이 됩니다.  에러는 아래와 같습니다. (이것도 순식간에 새로고침되면서 떳다가 사라져서 잡기가 힘들었습니다 ㅠ), 새로고침된 후에는 추가된 포스트가 정상적으로 load되기는 하는데요,

새로고침된다는게 큰 문제인것 같습니다..

components/postform.js에 onFinish를 onSubmit으로 바꾸고 event.preventDault()를 했을때는 아예 form제출도 되지 않아 이 문제는 아닌것같고, 다른 form은 새로고침이 발생안하는데 이것만 그렇네요.. 

query의 post.User.id 에 parseInt를 추가했는데, 이부분은 추가하던 안하던 똑같았습니다.

아래는 새로고침이 되는 과정에서 잠깐 떳다가 사라지는 console 메세지 입니다.

```
postcard.js:62 Uncaught TypeError: Cannot read property 'id' of undefined
    at PostCard (postcard.js:62)
    at renderWithHooks (react-dom.development.js:14803)
    at updateFunctionComponent (react-dom.development.js:17034)
    at beginWork (react-dom.development.js:18610)
    at HTMLUnknownElement.callCallback (react-dom.development.js:188)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
    at invokeGuardedCallback (react-dom.development.js:292)
    at beginWork$1 (react-dom.development.js:23203)
    at performUnitOfWork (react-dom.development.js:22154)
    at workLoopSync (react-dom.development.js:22130)
    at performSyncWorkOnRoot (react-dom.development.js:21756)
    at react-dom.development.js:11089
    at unstable_runWithPriority (scheduler.development.js:653)
    at runWithPriority$1 (react-dom.development.js:11039)
    at flushSyncCallbackQueueImpl (react-dom.development.js:11084)
    at flushSyncCallbackQueue (react-dom.development.js:11072)
    at batchedUpdates$1 (react-dom.development.js:21862)
    at Object.notify (Subscription.js:19)
    at Subscription.notifyNestedSubs (Subscription.js:92)
    at Subscription.handleChangeWrapper (Subscription.js:97)
    at Object.dispatch (redux.js:222)
    at e (<anonymous>:1:40553)
    at redux-saga-core.esm.js:1410
    at dispatch (redux.js:638)
    at io-6de156f3.js:133
    at redux-saga-core.esm.js:472
    at exec (redux-saga-core.esm.js:31)
    at flush (redux-saga-core.esm.js:87)
    at asap (redux-saga-core.esm.js:46)
    at runPutEffect (redux-saga-core.esm.js:468)
    at runEffect (redux-saga-core.esm.js:1204)
    at digestEffect (redux-saga-core.esm.js:1271)
    at next (redux-saga-core.esm.js:1161)
    at currCb (redux-saga-core.esm.js:1251)
index.js:1 The above error occurred in the <PostCard> component:
    in PostCard (at pages/index.js:22)
    in Home (created by NodeBird)
    in div (created by Context.Consumer)
    in Col (at AppLayout.js:63)
    in div (created by Context.Consumer)
    in Row (at AppLayout.js:59)
    in AppLayout (created by NodeBird)
    in Provider (created by NodeBird)
    in NodeBird (created by withRedux(NodeBird))
    in withRedux(NodeBird)
    in Container (created by AppContainer)
    in AppContainer

React will try to recreate this component tree from scratch using the error boundary you provided, Container.
index.js:1 Warning: Container: Error boundaries should implement getDerivedStateFromError(). In that method, return a state update to display an error message or fallback UI.
    in Container (created by AppContainer)
    in AppContainer
index.js:1 GET http://localhost:3060/%3Canonymous%3E 404 (Not Found)
index.js:1 GET http://localhost:3060/%3Canonymous%3E 404 (Not Found)
```

답변 12

2

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

useEffect 부분은 다시 빼시는 게 좋을 것 같습니다. 일단 post.User 부분은 해결했으니 큰 거 하나는 해결하신거고요.

다음 문제(리렌더링 안 되는 것)를 찾아봐야하는데 일단 개발자도구 devtool에서 mainPosts가 변화하는지 (폼 제출 시 ADD_POST_SUCCESS가 뜨면서 mainPosts에 하나가 추가되는지) 체크해보시고 알려주세요.

아마도 post.User도 undefined이고 한걸로 봐서는 ADD_POST_SUCCESS 액션에 문제가 있지 않나 추정됩니다.

이렇게 찾아가는 과정이 매우 괴로우시겠지만 이 과정을 잘 기억해두시면 도움이 될 것입니다 ㅠㅠㅠ

1

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

post.User.id가 에러가 나니 post.User && post.User.id 이렇게 보호연산자 적용해보세요. 최신문법으로는 post.User?.id 이렇게도 가능합니다.

1

stefan CHO님의 프로필 이미지
stefan CHO
질문자

post부분 다 빼고 "dummy"로 하닌깐 화면이 새로고침 안되네요, 그리고 dummy 갯수는 세어보닌깐 추가되었구요

routes쪽 보고있는데, 다 include된것 같은데.. 어딜 잘못한건지 아직 감이 잘 안잡히네요

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

제로초님 도움주셔서 감사합니다.

원인을 찾았는데 어이없게도... ADD_POST_SUCCESS의 put 부분에 data: "" 이렇게 해놨더라구요..

data : result.data로 하닌깐 잘 동작합니다. 위에 보호연산자를 안썼으면 진짜 못찾을 뻔했네요.. 새로고침을 막은덕에 리덕스 상태를 알수가 있었습니다. 아래는 제 개인노트에 정리한 내용 복붙입니다.

=====================================================

new post를 추가하여 form을 제출했는데, trouble shoot 15와 같은 에러가 계속 발생함 해결단계 :

1) post.User에 보호연산자를 통해 새로고침이 되는것을 먼저 막음

2) 새로고침이 되지 않기 때문에 Redux의 상태를 확인할 수 있었음

3) Redux상태를 보니 mainPosts에 diff가 빈값임을 확인함 (db내에는 저장이 되었지만, add post action을 하는 과정에서 mainPosts가 바로 업데이트 되지 못한것)

4) 원인 확인을 해보니 addpost의 saga에서 put을 하는데 거기에 data: "" 이렇게 비어있었음.. Redux로 확인해보니 diff에서 mainpost의 값이 빈 값으로 추가됨을 확인함.

5) ADD_POST_SUCCESS의 put값을 data: result.data로 변경 후 해결 (3일동안 고생, 제로초님 도움으로 실마리를 찾을 수 있었음) 

=====================================================

어떻게 딴곳을 다 뒤져봤는데 저기만 빼먹었을까요?... 딱 저기빼고 다 봤거든요 ㅠㅠ...

보호연산자를 빼도 정상동작합니다. 

도움주셔서 감사합니다!

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

index.js 에 useEffect추가했구요

import React, { useEffect, useState } from "react";
import Postform from "../components/postform";
import PostCard from "../components/postcard";
import { useSelector, useDispatch } from "react-redux";
import { LOAD_MAIN_POSTS_REQUEST } from "../reducers/post";

const Home = () => {
const { mainPosts, isAddedPost } = useSelector((state) => state.post);
const { me } = useSelector((state) => state.user);
const dispatch = useDispatch();
const [renderPosts, setRenderPosts] = useState(false);

useEffect(() => {
dispatch({
type: LOAD_MAIN_POSTS_REQUEST,
});
}, []);
useEffect(() => {
setRenderPosts(true);
}, [isAddedPost]);

return (
<React.Fragment>
{renderPosts}
{me && <Postform />}
{mainPosts.map((v, i) => {
return <PostCard key={+v.createdAt} post={v} />;
})}
</React.Fragment>
);
};

export default Home;

이건 postcard에다가 post.User 보호연산자 추가한 것입니다. Link랑 이런데에 직접적으로 추가하닌깐 없는상황에서 Link가 비어있다고 에러가 나서 Card전체에 post.User로 감쌋고 이러닌깐 새로고침 자체는 안생기는데, 포스트 추가가 안되네요(db상에는 추가되어 직접 새로고침하면 포스트가 나옵니다.)

import React, { useState, useCallback, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import Link from "next/link";
import { Card, Button, Avatar, Input, Comment, List, Form } from "antd";
import {
RetweetOutlined,
HeartOutlined,
MessageOutlined,
EllipsisOutlined,
} from "@ant-design/icons";
import { ADD_COMMENT_REQUEST, LOAD_MAIN_POSTS_REQUEST } from "../reducers/post";

const PostCard = ({ post }) => {
const [commentFormOpened, setCommentFormOpened] = useState(false);
const [commentText, setCommentText] = useState("");
const { me } = useSelector((state) => state.user);
const { isAddedComment, isAddingComment, isAddedPost } = useSelector(
(state) => state.post
);
const dispatch = useDispatch();

useEffect(() => {
// console.log("effect");
setCommentText("");
}, [isAddedComment === true]);

const onCommentToggle = useCallback(() => {
setCommentFormOpened((prev) => !prev);
}, []);

const onChangeCommentText = useCallback((e) => {
setCommentText(e.target.value);
}, []);

const onSubmitComment = useCallback(() => {
if (!me) {
return alert("Please Login First");
}
console.log("submit");
console.log(post.id);
return dispatch({ type: ADD_COMMENT_REQUEST, data: { postId: post.id } });
}, [me && me.id]);

return (
<div>
{post.User && (
<Card
key={+post.createdAt}
hoverable
style={{ width: 240, padding: 10, marginTop: 10 }}
cover={post.img && <img alt={post} src={post.img} />}
actions={[
<RetweetOutlined />,
<HeartOutlined />,
<MessageOutlined onClick={onCommentToggle} />,
<EllipsisOutlined />,
]}
extra={<Button>Follow</Button>}
>
<Card.Meta
avatar={
// <Avatar>{"dummy"}</Avatar>
<Link
href={
post.User && {
pathname: "/user",
query: { id: post.User.id },
}
}
as={post.User && `/user/${post.User.id}`}
>
<a>
<Avatar>{post.User && post.User.nickname[0]}</Avatar>
</a>
</Link>
}
// title="dummy"
title={post.User && post.User.nickname}
// description="dummy"
description={
post.User &&
post.content.split(/(#[^\s]+)/g).map((v) => {
if (v.includes("#")) {
const hashtag = v;
return (
<Link
key={v}
href={{
pathname: "/hashtag",
query: { tag: v.slice(1) },
}}
as={`/hashtag/${v.slice(1)}`}
>
<a>{hashtag}</a>
</Link>
);
} else {
return v;
}
})
}
></Card.Meta>
</Card>
)}
{commentFormOpened && (
<React.Fragment>
<Form onFinish={onSubmitComment}>
<Form.Item>
<Input.TextArea
rows={4}
value={commentText}
onChange={onChangeCommentText}
/>
</Form.Item>
<Button type="primary" htmlType="submit" loading={isAddingComment}>
Reply
</Button>
</Form>
<List
header={`${post.Comments ? post.Comments.length : 0} 댓글`}
itemLayout="horizontal"
dataSource={post.Comments || []}
renderItem={(item) => (
<li>
<Comment
author={item.userId}
avatar={<Avatar>{item.User.nickName[0]}</Avatar>}
content={item.content}
/>
</li>
)}
/>
</React.Fragment>
)}
</div>
);
};

export default PostCard;

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

post.User를 붙이닌깐 새로고침현상은 없어졌는데요,,

포스트가 다시 랜더링되면서 업데이트가 되야하는데, mainPosts 카드들이 그대로 있네요

그래서 renderPost라는 hooks state하나 만들어서 index.js에서 useEffect로 상태바꿔줬는데도

랜더링이 다시 안되네요..

컴포넌트 다시 랜더링하려면 이렇게 하는게 아닌가요?

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

post.User 이부분들을 "dummy"로 바꿨는데요(Link같은것들은 통으로 바꿔야하니 뺏습니다.)

그렇게 했을때는 에러가 없습니다. post.User때문에 에러가 생기는것같은데

분석에 진도가 잘 안나가지네요.. 뭘 더해보면 좋을까요

0

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

post 전체를 dummy로 바꾸지 마시고 post.User만 문자열같은걸로 바꿔보세요. 전체를 바꾸면 어떤 부분에서 에러가 있는지 알기 어려워집니다.

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

터미널 보면, newPost추가 후에 , 지금 fullpost내에 User정보가 들어있음을 볼수있습니다.

그리고, reducer에서 saga에서 받은 result.data값을 mainPosts: action.data로 넣어줬는데,

그러면 정상적으로 나와야하는거 같거든요...

0

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

post 안에 User가 안 들어있는 것 같은데 include하셨나요?? 그리고 post.User 부분 빼보시고 하셨을 때 에러나는지 확인해보세요.

0

stefan CHO님의 프로필 이미지
stefan CHO
질문자

네네, 제출전에는 콘솔에 아무 에러도 안뜹니다. 제출하는순간 저 에러가 새로고침되면서 순간적으로 잡혔다가 사라집니다. 

제가 모든 form에다가 onFinish로 해놨거든요,  

지금 하나씩 지우면서 해보고 있는데, 

post.User.nickname

post.User.id

처럼 post에서 타입에러가 발생하네요.

아래처럼 타입에러가 같은형태로 발생합니다. 자동으로 새로고침되면서 저 에러는 사라집니다.

form에서 제출할때는 괜찮은데, 제출하면서 postcard쪽에서 문제가 생기는 것 같습니다.

Uncaught TypeError: Cannot read property 'id' of undefined



Uncaught TypeError: Cannot read property 'nickname' of undefined

0

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

antd4버전에서 onSubmit -> onFinish가 되면서 e.preventDefault가 자동적용되었습니다. 그런데 제출 시 이게 안 된다는 것은 제출 이전에도 코드에 문제가 있다는 뜻입니다. 콘솔에 에러는 없나요?

stefan CHO님의 프로필 이미지
stefan CHO

작성한 질문수

질문하기