• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

saga axios.get 주소질문...............

20.05.04 15:16 작성 조회수 424

0

https://www.inflearn.com/questions/33218

다시 새롭게 질문드립니다,. 프론트상의 요청주소를 

"localhost:3060/post/100000(그룹id)" 로 하려고 전반적으로 수정하였고

부모자식관계가 있는 댓글부분을 참고해서  < routes / back>, < sagas / front > 거의 똑같이 만들었어요

"(게시물(Post)의 부모가되는)  GpostId 를 찾아서 게시물들 불러오기" 를 하고싶어서 아래와같이 코드를 작성했는데

posts/ undefined 가 뜹니다. saga 에서 loadMainPostsApi 에서  변수 gpostId를 제대로 정의하지못하는것같습니다..

******

댓글올리기 사이클이랑 거의 동일하게 해주었는데 ( 초록색빗금표시를 한부분의 코드 )

게시물불러오기가 안되는 이유가 뭘까요ㅠ??

******

< posts.js/ routes / back >

// 게시물'들' 불러오기
router.get('/:id'async (reqresnext=> { // GET /api/posts/100/개발자
  try {
    const gpost = await db.Gpost.findOne({ where: { id: req.params.id } }); 
    if (!gpost) {
      return res.status(404).send('포스트가 존재하지 않습니다.!!!!'); ///////////////////////////
    }//////////////////////////////////////////////////////////////////////////////////////////
    const posts = await db.Post.findAll({
      where: {
        GpostId: req.params.id,
      },
      include: [{
        model: db.User,
        attributes: ['id''nickname'],
      },{
        model: db.Image,
      },{
        model: db.User,
        through: 'Like',
        as:'Likers',
        attributes:['id'],
      }],
      order: [['createdAt''DESC']], // DESC는 내림차순, ASC는 오름차순
    });
    res.json(posts);
  } catch (e) {
    console.error(e);
    next(e);
  }
});

< post.js/ routes / back >

// 게시물 올리기 route : http://localhost:3060/post/개발자
router.post('/:id'isLoggedInupload.none(), async (reqresnext=>
  try {
    // 부모가되는 그룹포스트가있는지 /////////////////////////////////////////////
    const gpost = await db.Gpost.findOne({ where: { id: req.params.id } });
    if (!gpost) {
      return res.status(404).send('포스트가 존재하지 않습니다.????');
    }
    ///////////////////////////////////////////////////////////////////////////
    const newPost = await db.Post.create({
      content: req.body.content
      UserId: req.user.id,
      GpostId: gpost.id// 어떤 그룹에 속해있는지
    });
    await gpost.addPost(newPost.id);
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
    if (req.body.image) { // 이미지 주소를 여러개 올리면 image: [주소1, 주소2]
      if (Array.isArray(req.body.image)) {
        const images = await Promise.all(req.body.image.map((image=> {
          return db.Image.create({ src: image });
        }));
        await newPost.addImages(images);
      } else { // 이미지를 하나만 올리면 image: 주소1
        const image = await db.Image.create({ src: req.body.image });
        await newPost.addImage(image);
      }
    }
    const fullPost = await db.Post.findOne({
      where: { id: newPost.id },
      include: [{
        model: db.User,
        attributes: ['id''nickname'],
      },{
        model: db.Image,
      },{
        model:db.User,
        as:"Likers",
        attributes:['id'],
      }],
    });
    res.json(fullPost);
  } catch (e) {
    console.error(e);
    next(e);
  }
});

<<<<<<<<<<<<<<<<<< post.js/ sagas / front >>>>>>>>>>>>>>>>>>>>

// 게시물 올리기
function addPostAPI(postData){ // http://localhost:3060/post/10000 /////////////////////
    return axios.post(`/post/${postData.gpostId}`, { content: postData.content },{
        withCredentials: true //////////////////////////////////////////////////////////
   }); ////////////////////////////////////////////////////////////////////////////////
}
function* addPost(action) {
    try {
      const result = yield call(addPostAPIaction.data);
      yield put({
        type: ADD_POST_SUCCESS,
        data: { ////////////////////////////////////////////////////////////////
          gpostId: action.data.gpostId,
          content: result.data,
        },//////////////////////////////////////////////////////////////////////
      });
      console.error(e);
    } catch (e) {
      yield put({
        type: ADD_POST_FAILURE,
        error: e,
      });
    }
}
function* watchAddPost(){
    yield takeLatest(ADD_POST_REQUESTaddPost);
}

// 게시물 로드하기
function loadMainPostsAPI(gpostId) { // http://localhost:3060/post/10000
    return axios.get(`/posts/${gpostId}`); //////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
function* loadMainPosts(action) {
    try {
      const result = yield call(loadMainPostsAPIaction.data);
      yield put({
        type: LOAD_MAIN_POSTS_SUCCESS,
        data: {
          gpostId: action.data,
          content: result.data,
        },
      });
    } catch (e) {
      yield put({
        type: LOAD_MAIN_POSTS_FAILURE,
        error: e,
      });
    }
}  
function* watchLoadMainPosts() {
    yield takeLatest(LOAD_MAIN_POSTS_REQUESTloadMainPosts);
}

< server.js / front>

  server.get('/post/:id', (reqres=> { // http://localhost:3060/post/1000000
    return app.render(reqres'/posted', { id: req.params.id });
 });

< posted.js / pages / front >  -  server.js 에서 연결해주는 동적페이지 

// 그룹: 동적페이지
const Posted = () => {
    .
.
.
    return (
        <>
            <div className="wrap">
                {/* GpostId와 그룹의 id가 같을경우에만 화면에 표시 */}
                {GroupPosts.map((val)=>{
                    var gid = window.location.href.split("/").reverse()[0];
                    ifgid == val.id){
                        return(
                            <div>
                                <GroupBox gpost={val} gimg={val.GImgs} /><UploadForm gpost={val} />
                            </div>
                        );
                    }
                })}
            </div>
        </>
    );
};

Posted.getInitialProps = async (context=> {
    console.log('posted getInitialProps'context.query.title);
};
export default Posted;

<  UploadForm.js / Component / front > - 게시물올리는 컴포넌트 onSubmitForm 함수부분

const onSubmitForm = useCallback((e=> {
        e.preventDefault();
        if (!text || !text.trim()) {
          return alert('게시글을 작성하세요.');
        }
        const formData = new FormData();
        imagePaths.forEach((i=> {
          formData.append('image'i);
        });
        formData.append('content'text); ////////////////////////////////////////////////////
        formData.append('GpostId'gpost.id); //////////////////// <- //////////////////////////
        dispatch({ ////////////////////////////////////////////////////
          type: ADD_POST_REQUEST,
          data: formData,
        });
      }, [textimagePathsgpost.id]);

< post.js /reducers / front >

// 게시물 불러오기
        case LOAD_MAIN_POSTS_REQUEST: {
            return {
              ...state,
              mainPosts: [],
            };
          }
        case LOAD_MAIN_POSTS_SUCCESS: {
            return {
              ...state,
              mainPosts: action.data,
            };
          }
        case LOAD_MAIN_POSTS_FAILURE: {
            return {
                  ...state,
            };
       }

< WorkBench >  -  GpostId 의 파란색부분은 워크벤치에서 임의로 넣어주었습니다.

+ 노드 백서버 오류메세지입니다

답변 11

·

답변을 작성해보세요.

1

cttf가 undefined인 경우를 대비 안 하신것 같네요. cttf && cttf.map((i) => {로 고치세요.

0

지니님의 프로필

지니

질문자

2020.05.06

감사합니다!!!ㅠㅠ

0

&&은 앞의 값이 truthy value인 경우에 뒤로 넘어가라는 의미입니다.

0

지니님의 프로필

지니

질문자

2020.05.05

!!! ㅜㅠㅠㅠ 잘뜹니다 감사합니다ㅜ

cttf !== undefined && cttf.map((i)=>{

이렇게 해줘도 뜨는데 

cttf  && cttf.map 이랑 뜻이 다른가요??

0

지니님의 프로필

지니

질문자

2020.05.05

cttf 에 관련해선 딱히 오류뜨는게 없어요ㅜ

아래처럼 코드 수정후에 다시 실행시켜봤더니 화면에 잘 나왔다가

TypeError: Cannot read property 'map' of undefined오류가 번갈아가면서 뜨네요

var cttf = mainPosts.content;

{ cttf.map((i)=>{
    return(
         <ContentForm key={i} post={i} />
    );
})}

0

에러 메시지가 뭔가요. cttf 관련해서요.

0

지니님의 프로필

지니

질문자

2020.05.05

map 과 관련된 구글사이트 읽어봐도 문제점을 찾지못해질문남깁니다..

0

지니님의 프로필

지니

질문자

2020.05.05

감사합니다!!

useEffect 로 dispatch 하는 부분에 data에 gpost의 id 값넣어주니 LOAD_MAIN_POSTS_SUCCESS 가 뜨네요!

그런데 mainPosts.map 으로 게시물을 화면에 렌더링 했었는데

 TypeError: mainPosts.map is not a function     

라고 오류가 뜹니다.

콘솔로 mainPosts 찍어보니 saga에서 보내주는 구조로 data값이 전달되는것을 확인했습니다.

그래서 cttf 라는 변수에 content만 담아서 map으로 리턴 시켜주려 했는데 여전히 타입에러 오류메세지가 떠요..

cttf = mainPosts.content;

구조가 getinitialprops로 연동된 페이지(posted페이지) 안에있는 컴포넌트:<UploadForm>의

자식컴포넌트:<ContentForm>을 map으로 리턴해주려 하고 있습니다.

컴포넌트 <UploadForm> 에서는 인자로 { gpost }로 그룹의 데이터를 받아오고

컴포넌트 <ContentForm> 에서는 인자로 { post } 로 게시물의 데이터를 받게 Proptype 설정을 해주었어요

*****

뭐때문에 생기는 오류인지 알고싶습니다.!!

컴포넌트 코드 입니다.

const UploadForm = ({gpost}) => {
    const dispatch = useDispatch();

    const [textsetText ] = useState('');
    const { isAddingPostpostAddedmainPostsimagePaths } = useSelector(state => state.post);
    const imageInput = useRef();

    // 게시물 로드하기
    // useEffect(() => {
    //     dispatch({
    //       type: LOAD_MAIN_POSTS_REQUEST,
    //       data: gpost.id,
    //     });
    //   }, []);

    useEffect(() => {
        setText('');
    },[postAdded === true]);

    const onSubmitForm = useCallback((e=> {
        e.preventDefault();
        if (!text || !text.trim()) {
          return alert('게시글을 작성하세요.');
        }
        const formData = new FormData();
        imagePaths.forEach((i=> {
          formData.append('image'i);
        });
        formData.append('content'text);
        formData.append('GpostId'gpost.id);
        dispatch({
          type: ADD_POST_REQUEST,
          data: formData,
        });
      }, [textimagePathsgpost.id]);
      
     // 이미지업로드
     const onChangeImages = useCallback((e=> {
        console.log(e.target.files);
        const imageFormData = new FormData();
        [].forEach.call(e.target.files, (f=> {
          imageFormData.append('image'f);
        });
        dispatch({
          type: UPLOAD_IMAGES_REQUEST,
          data: imageFormData,
        });
      }, []);
    
    
    var cttf;


    return (
        <div>
          <form>부분
            {/* 게시물올라가는부분 */}
            <div className="letsbegin">
                <div>
                    {(()=>{
                        console.log("mainPosts : ",mainPosts);
                        cttf = mainPosts.content;
                        cttf.map((i)=>{
                            <ContentForm key={i} post={i} />
                        });
                    })()}
                    
                    {/* {mainPosts.map((i)=>{
                        return(
                            <ContentForm key={i} post={i} />
                        );
                    })} */}

                </div>
            </div>
            
        </div>
    );
};

UploadForm.propTypes={
    gpost: PropTypes.shape({
        User: PropTypes.object,
        title: PropTypes.string,
    }),
};

export default UploadForm;

const ContentForm = ({post}) => {
    const [commentFormOpenedsetCommentFormOpened] = useState(false);
    const [commentTextsetCommentText ] = useState('');

    const { me } = useSelector(state => state.user);
    const { commentAddedisAddingComment } = useSelector(state => state.post);
    const dispatch = useDispatch();
    
    const liked = me && post.Likers && post.Likers.find(v => v.id === me.id);

    
    //댓글창토글
    const onToggleComment = useCallback(() => {
        setCommentFormOpened(prev => !prev);
        if (!commentFormOpened) { 
          // 댓글창 켤때 불러오기
            dispatch({
              type: LOAD_COMMENTS_REQUEST,
              data: post.id,
            });
          }
      }, []);

    // 댓글
    const onChangeComment = useCallback((e=> {
        setCommentText(e.target.value);
    }, []);

    // 댓글올리기 사이클
    const onSubmitComment = useCallback((e=> {
        e.preventDefault();
        if(!me){
            return alert('로그인이 필요합니다.');
        }
        return dispatch({
            type: ADD_COMMENT_REQUEST,
            data:{
                PostId: post.id,
                content: commentText,
            },
        });
    }, [me && me.idcommentText]);
    
    // 댓글 성공시, 빈텍스트로 
    useEffect(() => {
        setCommentText('');
    },[commentAdded === true]);

    // 댓글삭제하기
    const onRemoveComments = useCallback(userId => () => {
        alert('댓글을 삭제하시겠습니까?');
        // console.log("포스트아이디",me.id, post.User.id)
        if(me.id === post.User.id)
        dispatch({
          type: REMOVE_COMMENT_REQUEST,
          data: userId,
        });
    });

    // 댓글 변수선언
    var listIndex;

    // 게시글 삭제
    const onRemovePost = useCallback(userId => () => {
        // console.log("포스트아이디",me.id, post.User.id)
        if(me.id === post.User.id)
        alert('게시물을 삭제하시겠습니까?');
        dispatch({
          type: REMOVE_POST_REQUEST,
          data: userId,
        });
        if(me.id !== post.User.id)
        alert('다른 사용자의 게시물은 삭제할 수 없습니다.');
    });
  
    // 좋아요 토글
    const onToggleLike = useCallback(() => {
        if (!me) {
          return alert('로그인이 필요합니다!');
        }
        if (liked) { // 좋아요 누른 상태
          dispatch({
            type: UNLIKE_POST_REQUEST,
            data: post.id,
          });
        } else { // 좋아요 안 누른 상태
          dispatch({
            type: LIKE_POST_REQUEST,
            data: post.id,
          });
        }
    }, [me && me.idpost && post.idliked]);
  

    return(
        <>
            <div className="postbox">   
                <div className="contBox">
                <p>{post.User.nickname} 님의 게시물 - 좋아요 : {post.Likers.length }  </p>
                    <PostImages images={post.Images} />
                    <div>{post.content}</div>
                </div>
                <div className="btnsbox">
                    <button type="button" className="commentBtn"  value={commentFormOpened} onClick={onToggleComment} />
                    { liked ? <button type="button" className="likeBtnred" onClick={onToggleLike} /> :
                    <button type="button" className="likeBtnline" onClick={onToggleLike} /> } 
                    <button type="button" className="removeBtn" onClick={onRemovePost(post.id)} />
                    {commentFormOpened===true &&
                        <form className="commentbox" onSubmit={onSubmitComment}>
                            <textarea className="comment" value={commentText} onChange={onChangeComment} />
                            <button type="primary" htmlType="submit" className="combtn" loading={isAddingComment} >COMMENT</button>
                        </form>
                    }
                    {/* 댓글올라갈부분 */}
                    {commentFormOpened===true && (
                        <div style={{display:"inline-block"width:"100%"}}>
                            <p style={{marginLeft:"10px"}}>{commentAdded ? '댓글' + post.Comments.length : '댓글''0'}</p>
                            <div className="comline"></div>
                            
                            {(()=>{
                                if(post.Comments){
                                    // console.log(post.Comments[0])
                                    listIndex = post.Comments.map((el)=>
                                        (
                                        <li style={{listStyle:"none"display:"inline-block"clear:"both"}} >
                                            {el.User.nickname} : {el.content} 
                                            { el.User.id === me.id ? 
                                            <button type="button" className="remove" onClick={onRemoveComments(post.id)} > REMOVE </button>
                                            : "" }
                                        </li>
                                        )
                                   )
                                }
                                return(
                                    <ul> 
                                        {listIndex} 
                                    </ul>
                                );
                            })()}
                            
                        </div>
                        )
                    }
                </div> 
            </div>
        </>
    );
    

};

ContentForm.propTypes={
    post: PropTypes.shape({
        User: PropTypes.object,
        content: PropTypes.string,
        createdAt: PropTypes.string,
    }),
};


export default ContentForm;

0

dispatch하는 부분요. 그리고 axios 요청하는 부분도 같이 살펴보시면 됩니다. 문제 발생위치가 프론트인지 서버인지부터 구뷴하시면 됩니다.

0

지니님의 프로필

지니

질문자

2020.05.04

saga //  routes // reducer 중 어느부분말씀하시는건가요?..?

0

api/posts/아이디는 load main posts request부분인데 그 부분은 안 올리셨네요. action.data가 undefined입니다.