ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Social Media 만들기 - 12) get posts 가져오기
    NODE.JS 2021. 7. 12. 01:33

    이제 홈페이지에 포스트를 가지고 와서 보여주도록 하자. 

    포스트를 가지고 오는 라우터를 먼저 작성해준다. 

    (auth 미들웨어에서 req.user = user로 등록해줬다)이를 이용한다. 

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

     

    postConstants

    export const GET_HOME_POSTS_REQUEST = 'GET_HOME_POSTS_REQUEST'
    export const GET_HOME_POSTS_SUCCESS = 'GET_HOME_POSTS_SUCCESS'
    export const GET_HOME_POSTS_FAIL = 'GET_HOME_POSTS_FAIL'
    
    export const GET_POSTS_RESET = 'GET_POSTS_RESET'

     

    postActions을 만들어준다. 

    export const getHomePosts =() => async(dispatch, getState)=>{
    
        
        dispatch({
            type:GET_HOME_POSTS_REQUEST,
            payload:{loading:true}
        })
    
        const {userLogin: {userInfo}} = getState()
    
        try{
            const res = await axios.get('/api/post',{headers: {authorization : `Bearer ${userInfo.token}`}})
            
            console.log(res.data.posts)
            dispatch({
                type:GET_HOME_POSTS_SUCCESS,
                payload:res.data.posts
            })
    
        }catch(error){
            dispatch({
                type:GET_HOME_POSTS_FAIL,
                payload:                
                error.response && error.response.data.message
                ? error.response.data.message
                : error.message
            })
        }
    }

    post Reducers

    export const postGetReducer = (state={}, action)=>{
        switch(action.type){
            case GET_HOME_POSTS_REQUEST:
                return {loading:true}
            case GET_HOME_POSTS_SUCCESS:
                return {loading:false, posts:action.payload, success:true}
            case GET_HOME_POSTS_FAIL:
                return {loading:false, error:action.payload, success:false}
            case GET_POSTS_RESET:
                return {}
            default:
                return state
        }
    }

     

    store.js

        getposts:postGetReducer,

     

    이제 포스트를 가지고 오도록하자. 

    Post 컴포넌트에 다음과 같이 입력해준다. 

    포스트를 생성완료하면 생성된 포스트 가지고 오도록 설정해준다. 

    import React, { useEffect, useState } from 'react'
    import { useDispatch, useSelector } from 'react-redux'
    import { createPost, getHomePosts } from '../_actions/postActions'
    import { GET_POSTS_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
    
        useEffect(() => {
            if(success){
                dispatch({type:GET_POSTS_RESET})
                dispatch({type:CREATE_POST_RESET})
    
            }
            dispatch(getHomePosts())
        }, [dispatch, success])
    
        return (
            <div className="posts">
                {
                    posts && 
                    posts.map(post=>(
                        <PostCard key={post._id} post={post}></PostCard> 
                    ))
                }
            </div>
        )
    }
    
    export default Post

     

    이제 포스트 카드 부분을 짜줄 것이다. 

    포스트카드는 카드헤더, 바디, 풋터, 커맨트 , 인풋 부분으로 나눠줄 것이다. 

    import CardHeader from './post_card/CardHeader'
    import CardBody from './post_card/CardBody'
    import CardFooter from './post_card/CardFooter'
    import Comments from './post_card/Comments'
    import InputComment from './post_card/InputComment'
    
    import React from 'react'
    
    function PostCard({post}) {
        return (
            <div className="card my-3">
                <CardHeader post = {post}/>
                <CardBody post = {post} />
                <CardFooter post = {post} />
    
                <Comments post = {post} />
                <InputComment Comment = {post} />
    
            </div>
        )
    }
    
    export default PostCard

     

     

     

    CardHeader.js

    여기서 moment를 사용하기 위해서 npm i moment 해준다. (시간 사용한다)

    import React from 'react'
    import Avatar from '../Avatar'
    import {Link}  from 'react-router-dom'
    import moment from 'moment'
    import { useDispatch, useSelector } from 'react-redux'
    
    function CardHeader({post}) {
        const userLogin = useSelector(state => state.userLogin)
        const {userInfo} = userLogin
    
        const dispatch = useDispatch()
    
        const handleEditPost = () =>{
            
    
        }
    
        return (
            <div className="card_header">
                <div className="d-flex">
                    <Avatar src={post.user.avatar} size="big-avatar"/>
                    <div className="card_name">
                        <h6 className="m-0">
                            <Link to={`/profile/${post.user._id}`} className="text-dark">
                                {post.user.username}
                            </Link>
                        </h6>
                        <small className="text-muted">
                            {moment(post.createdAt).fromNow()}
                        </small>
                    </div>
                </div>
    
                <div className="nav-item dropdown">
                    <span className="material-icons" id="moreLink" data-toggle="dropdown">
                        more_horiz
                    </span>
                    <div className="dropdown-menu">
                        {
                            userInfo.user._id ===post.user._id &&
                            <>
                                <div className="dropdown-item">
                                    <span className="material-icons" onClick={handleEditPost}>create</span> Edit Post
                                </div>
                                <div className="dropdown-item">
                                    <span className="material-icons">delete_outline</span> Remove Post
                                </div>
                            </>
                        }
                        <div className="dropdown-item">
                            <span className="material-icons">content_copy</span> Copy Link
                        </div>
                    </div>
                </div>
            </div>
        )
    }
    
    export default CardHeader

     

    CardBody.js

    import React, { useState } from 'react'
    import Carousel from '../Carousel'
    
    function CardBody({post}) {
    
        const [readMore, setReadMore] = useState(false)
        return (
            <div className="card_body">
                <div className="card_body-content">
                    <span>
                        {
                            post.content.length<60
                            ? post.content
                            : readMore? post.content + ' ' : post.content.slice(0,60) + '.....'
                        }
                    </span>
                    {
                        post.content.length >60 &&
                        <span className="readMore" onClick={()=>setReadMore(!readMore)}>
                            {readMore? 'Hide content' : 'Read more'}
                        </span>
                    }
                </div>
                {
                    post.images.length>0 && <Carousel images={post.images}  id={post._id}/>
                }
            </div>
        )
    }
    
    export default CardBody

     

    이미지를 보여주는 Carousel을 작성하도록 하자. 

    부트스트랩의 Carousel을 이용한다. 

    import React from 'react'
    import { useSelector } from 'react-redux'
    
    function Carousel({images, id}) {
        const isActive = index=>{
            if(index===0) return "active"
        }
    
        const theme = useSelector(state => state.theme)
        
        return (
            <div id={`image${id}`} className="carousel slide" data-ride="carousel">
                <ol className="carousel-indicators" style={{zIndex: 1}}>
                    {
                        images.map((img, index) => (
                            <li key={index} data-target={`#image${id}`} 
                            data-slide-to={index} className={isActive(index)} />
                        ))
                    }
                    
                </ol>
    
                <div className="carousel-inner">
                    {
                        images.map((img, index) => (
                            <div key={index} className={`carousel-item ${isActive(index)}`}>
                                {
                                    img.data.match(/video/i)
                                    ? <video controls src={img.data} className="d-block w-100" alt={img.data}
                                    style={{filter: theme ? 'invert(1)' : 'invert(0)'}} />
    
                                    : <img src={img.data} className="d-block w-100" alt={img.data}
                                    style={{filter: theme ? 'invert(1)' : 'invert(0)'}} />
                                }
                               
                            </div>
                        ))
                    }
                    
                </div>
                
                {
                    images.length > 1 &&
                    <>
                        <a className="carousel-control-prev" href={`#image${id}`} role="button" data-slide="prev"
                        style={{width: '5%'}}>
                            <span className="carousel-control-prev-icon" aria-hidden="true"></span>
                            <span className="sr-only">Previous</span>
                        </a>
    
                        <a className="carousel-control-next" href={`#image${id}`} role="button" data-slide="next"
                        style={{width: '5%'}}>
                            <span className="carousel-control-next-icon" aria-hidden="true"></span>
                            <span className="sr-only">Next</span>
                        </a>
                    </>
                }
                
            </div>
        )
    }
    
    export default Carousel

     

    CardFooter.js

    import React from 'react'
    import {Link} from 'react-router-dom'
    import Send from '../../images/send.svg'
    
    function CardFooter({post}) {
        return (
            <div className="card_footer">
                <div className="card_icon_menu">
                    <div>
                        <i className="far fa-heart"></i>
                        <Link to={`/post/${post._id}`} className="text-dark">
                            <i className="far fa-comment"></i>
                        </Link>
    
                        <img src={Send} alt="Send" />
    
                    </div>
    
                    <i className="far fa-bookmark"></i>
                </div>
    
                <div className="d-flex justify-content-between">
                    <h6 style={{padding: '0 25px', cursor:'pointer'}}>{post.likes.length}</h6>
                    <h6 style={{padding: '0 25px', cursor:'pointer'}}>{post.comments.length} comments</h6>
                </div>
            </div>
        )
    }
    
    export default CardFooter

    잘 작동한다. 

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.