ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Social Media 만들기 - 16) profile post, detail post 구현하기
    NODE.JS 2021. 7. 19. 22:22

    이제 유저프로필 페이지에서 해당 user의 포스트를 가져오자. 

     

    유저아이디에 해당하는 포스트를 가져오는 Router를 작성한다. 

    postRouter.get('/user/:id', auth, async(req, res)=>{
        try{
            const posts = await Post.find({user: req.params.id})
                                    .sort("-createdAt")
                                    .populate("user likes", "avatar username fullname followers following")
                                    .populate({
                                        path:"comments",
                                        populate:{
                                            path:"user likes",
                                            select:"-password"
                                        },
                                        sort:'-createdAt'
                                    })
    
            res.json({posts})
        }catch(err){
            return res.status(500).json({message:err.message})
        }
    })

     

     

    profile.constants.js

    export const PROFILE_GETPOST_SUCCESS='PROFILE_GETPOST_SUCCESS'

     

     

    profileuser를 가져오는 코드에 다음과 같이 post를 가져오는 코드를 추가해준다. 

    export const getProfileUser = (userId)=>async (dispatch, getState)=>{
        dispatch({
            type:PROFILE_GETUSER_REQUEST,
            payload:userId
        })
        const {userLogin:{userInfo}} = getState()
        try{
            const {data} = await axios.get(`/api/users/${userId}`,{headers:{authorization : `Bearer ${userInfo?.token}`}
            })
    
            const res = await axios.get(`/api/post/user/${userId}`,{headers: {authorization : `Bearer ${userInfo.token}`}})
    
    
            dispatch({
                type:PROFILE_GETUSER_SUCCESS,
                payload:data
            })
    
            dispatch({
                type:PROFILE_GETPOST_SUCCESS,
                payload:res.data.posts
            })
    
    
        }catch (err){
            dispatch({
                type:PROFILE_GETUSER_FAIL,
                payload:{error:err.response && err.response.data.message? err.response.data.message : err.message}
            })
        }
    }

     

     

     

    profileReducer에 다음과 같이 post정보를 추가해준다. 

    export const getUserProfileReducer = (state={}, action)=>{
        switch(action.type){
            case PROFILE_GETUSER_REQUEST:
                return {loading:true};
            case PROFILE_GETUSER_SUCCESS:
                return {loading:false, user:action.payload}
            case PROFILE_GETUSER_FAIL:
                return {loading:false, error:action.payload}
            case PROFILE_GETUSER_RESET:
                return {loading:true}
            case USER_FOLLOW_PROFILE:
                return {...state, user:action.payload}
            case USER_UNFOLLOW_PROFILE:
                return {...state, user:action.payload}
            case PROFILE_GETPOST_SUCCESS:
                return {...state, posts:action.payload}
            default:
                return state;
        }
    }

     

     

    profile.js에서 디스패치 해서 가져온 user 정보의 post를 읽어서 post thumb요소를 이용해서 보여준다. 

    import React, { useEffect, useState } from 'react'
    import { useDispatch, useSelector } from 'react-redux';
    import { getProfileUser } from '../_actions/profileActions';
    import Avatar from '../component/Avatar'
    import { PROFILE_GETUSER_RESET, USER_UPDATE_PROFILE_RESET } from '../_constants/profileConstants';
    import Loading from '../component/Loading';
    import Alert from '../component/Alert'
    import EditProfile from '../component/EditProfile'
    import FollowBtn from '../component/FollowBtn';
    import Followers from '../component/Followers';
    import Followings from '../component/Followings';
    import Post from '../component/Post';
    import {Link} from 'react-router-dom'
    
    
    function Profile(props) {
        const userId = props.match.params.id;
       
    
        const userProfile = useSelector(state => state.userProfile)
        const {loading, error, user, posts} = userProfile
    
        useEffect(() => {
            if(!user || userId !== user._id || success){
                dispatch({
                    type:PROFILE_GETUSER_RESET
                })
                dispatch({
                    type:USER_UPDATE_PROFILE_RESET
                })
                dispatch(getProfileUser(userId))
            }
        }, [dispatch, userId, user, userInfo.token,success])
    
        return (
    
                {
                    posts && posts.length ===0
                    ? <h2 className="text-center text-danger">NO POST</h2>
                    : <>
                    <div className="post_thumb">
                        {
                            posts?.map(post=>(
                                <Link key={post._id} to={`/post/${post._id}`}>
                                    <div className="post_thumb_display">
                                        {
                                            post.images[0].config.url.match(/video/i)
                                            ? <video controls src={post.images[0].data} alt={post.images[0].data}></video>
                                            : <img src={post.images[0].data} alt={post.images[0].data}></img>
                                        }
    
                                        <div className="post_thumb_menu">
                                            <i className="far fa-heart"></i>
                                            <i className="far fa-comment"></i>
                                        </div>
                                    </div>
                                </Link>
                            ))
                        }
                    </div>
                    </>
    
                }
            </div>
        )
    }
    
    export default Profile

     

     

    post thumb.css

    .post_thumb{
        width: 100%;
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        justify-content: center;
        grid-gap: 10px;
        overflow: hidden;
        margin: 15px 0;
    }
    .post_thumb_display{
        min-width: 300px;
        height: 300px;
        width: 100%;
        position: relative;
        cursor: pointer;
        overflow: hidden;
    }
    .post_thumb_display img,
    .post_thumb_display video{
        width: 100%;
        height: 100%;
        display: block;
        object-fit: cover;
    }
    .post_thumb_display .post_thumb_menu{
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: #0008;
        display: flex;
        justify-content: center;
        align-items: center;
        opacity: 0;
        transition: 0.3s;
    }
    .post_thumb_display:hover .post_thumb_menu{
        opacity: 1;
    }
    .post_thumb_display .post_thumb_menu i{
        font-size: 1.8rem;
        color: white;
        margin: 0 25px;
    }

     

    GLOBAL에도 추가해준다. 

    /* -------- PostThumb ---------- */
    @import url("./post_thumb.css");

    리덕스에도 잘 생겼다. 

     

     

    사진을 누르면 링크를 통해서 이동하도록 했으니, 

    App.js에 다음과 같이 추가해주자. 

              <Route exact path="/post/:id" component={Post}/>

     

    pages>Post.js를 만들어준다. 

    import React from 'react'
    
    function Post(props) {
    
        const postId = props.match.params.id;
    
        
        return (
            <div>
                Post
            </div>
        )
    }
    
    export default Post

     

    router를 만들어주자. 

    postRouter.get('/:id', auth, async(req, res)=>{
    
    
        try{
            const post = await Post.findById(req.params.id)
                                    .sort('-createdAt')
                                    .populate("user likes", "avatar username fullname followers following")
                                    .populate({
                                        path:"comments",
                                        populate:{
                                            path:"user likes",
                                            select:"-password"
                                        },
                                        sort:'-createdAt'
                                    })
            if(!post) return res.status(400).json({msg:"This post does not exist."})
    
            res.json({post})
    
        }catch(err){
            return res.status(500).json({message:err.message})
        }
        
    })

     

    constant

    export const GET_POST_REQUEST = 'GET_POST_REQUEST'
    export const GET_POST_SUCCESS = 'GET_POST_SUCCESS'
    export const GET_POST_FAIL = 'GET_POST_FAIL'

     

     

    action

    export const getPostDetail =(postId) => async(dispatch, getState)=>{
    
        
        dispatch({
            type:GET_POST_REQUEST,
            payload:{loading:true}
        })
    
        const {userLogin: {userInfo}} = getState()
    
        try{
            const res = await axios.get(`/api/post/${postId}`,{headers: {authorization : `Bearer ${userInfo.token}`}})
            
            
            dispatch({
                type:GET_POST_SUCCESS,
                payload:res.data.post
            })
    
        }catch(error){
            dispatch({
                type:GET_POST_FAIL,
                payload:                
                error.response && error.response.data.message
                ? error.response.data.message
                : error.message
            })
        }
    }

     

     

    reducer

    export const postDetailReducer = (state={}, action)=>{
        switch(action.type){
            case GET_POST_REQUEST:
                return {loading:true, success:false}
            case GET_POST_SUCCESS:
                return {loading:false, success:true, postdetail:action.payload}
            case GET_POST_FAIL:
                return {loading:false, success:false, error:action.payload}
            default:
                return state
        }
    }

     

     

    store.js

        detailpost:postDetailReducer,

     

    post.js

    업데이트 되면 그대로 가져와서 새로바꿔진 데이터 가져오도록 설정한다. 

    import React, { useEffect, useState } from 'react'
    import { useDispatch, useSelector } from 'react-redux'
    import { createPost, getHomePosts } from '../_actions/postActions'
    import { CREATE_POST_RESET, DELETE_POST_RESET, GET_POSTS_RESET, LIKE_POST_RESET, UNLIKE_POST_RESET, UPDATE_POST_RESET } from '../_constants/postConstants'
    import PostCard from './PostCard'
    
    function Post() {
    
        const userLogin = useSelector(state => state.userLogin)
        const {userInfo} = userLogin
    
        const dispatch = useDispatch()
    
        const getposts = useSelector(state => state.getposts)
        const {posts} = getposts
    
        const createpost = useSelector(state => state.createpost)
        const {success} = createpost
        
        const updatepost = useSelector(state => state.updatepost)
        const{success:updatesuccess}  = updatepost
    
        const deletepost = useSelector(state => state.deletepost)
        const {success:deletesuccess} = deletepost
        
        const likepost = useSelector(state => state.likepost)
        const {success:likesuccess} = likepost
    
        const unlikepost = useSelector(state => state.unlikepost)
        const {success:unlikesuccess} = unlikepost
    
    
    
        useEffect(() => {
            if(success||updatesuccess ||deletesuccess ||unlikesuccess ||likesuccess){
                dispatch({type:GET_POSTS_RESET})
                dispatch({type:CREATE_POST_RESET})
                dispatch({type:UPDATE_POST_RESET})
                dispatch({type:DELETE_POST_RESET})
                dispatch({type:LIKE_POST_RESET})
                dispatch({type:UNLIKE_POST_RESET})
            }
    
            dispatch(getHomePosts())
        }, [dispatch, success, updatesuccess, deletesuccess, unlikesuccess, likesuccess])
    
        return (
            <div className="posts">
                {
                    posts && 
                    posts.map(post=>(
                        <PostCard key={post._id} post={post}></PostCard> 
                    ))
                }
            </div>
        )
    }
    
    export default Post

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.