ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Social Media 만들기 - 16) Discover - loadmore 버튼 구현하기
    NODE.JS 2021. 7. 30. 23:30

     

    loadmore 버튼을 구현해보자. 

     

    discoverRouter를 만들어준다. 

    파일을 랜덤으로 num(로드모어 버튼 누를때마다 페이지수 증가 * limit)

    const express = require('express')
    const {Post} = require('../models/Post')
    const {auth} = require('../middleware/auth')
    const { User } = require('../models/User')
    
    
    
    const discoverRouter = express.Router()
    
    discoverRouter.get('/', auth, async(req, res)=>{
        try{
    
            const user = await User.findOne({_id:req.user.id})
            const newArr=[...user.following, req.user.id]
    
            const num = req.query.num || 9;
    
            const posts= await Post.aggregate([
                {$match: {user:{$nin: newArr}}},
                {$sample: {size:Number(num)}},
            ])
    
            return res.json({
                result:posts.length,
                posts
            })
    
    
        }catch(err){
            return res.status(500).json({message:err.message})
        }
        
    })
    module.exports = discoverRouter

    server.js

    app.use('/api/discover', require('./routes/discoverRouter'));

     

    postconstants.js

    export const GET_DISCOVER_POST_REQUEST = 'GET_DISCOVER_POST_REQUEST'
    export const GET_DISCOVER_POST_SUCCESS = 'GET_DISCOVER_POST_SUCCESS'
    export const GET_DISCOVER_POST_FAIL = 'GET_DISCOVER_POST_FAIL'
    export const GET_DISCOVER_POST_UPDATE = 'GET_DISCOVER_POST_UPDATE'

     

    postActions.js

    export const getDiscoverPost= ()=>async(dispatch, getState)=>{
        dispatch({
            type:GET_DISCOVER_POST_REQUEST,
            payload:{loading:true}
        })
    
        const {userLogin: {userInfo}} = getState();
        try{
           const res = await axios.get('/api/discover',{
                headers:{authorization:`Bearer ${userInfo.token}`},
            })
    
    
            dispatch({
                type:GET_DISCOVER_POST_SUCCESS,
                payload:{posts:res.data.posts, result:res.data.result}
            })
    
        }catch(error){
            dispatch({
                type:GET_DISCOVER_POST_FAIL,
                payload:                
                error.response && error.response.data.message
                ? error.response.data.message
                : error.message
            })
        }
    }

     

     

    postReducer.js

    export const postDiscoverReducer = (state={}, action)=>{
        switch(action.type){
            case GET_DISCOVER_POST_REQUEST:
                return {...state,   loading:true, success:false}
            case GET_DISCOVER_POST_SUCCESS:
                return {...state,loading:false, success:true, discoverpost:[...action.payload.posts], result:action.payload.result, firstLoad:true}
            case GET_DISCOVER_POST_FAIL:
                return {...state,loading:false, success:false, error:action.payload}
            case GET_DISCOVER_POST_UPDATE:
                return {...state, discoverpost:action.payload.posts, result:action.payload.result}
            default:
                return state
        }
    }

     

     

    store.js

       discoverpost:postDiscoverReducer,

     

    Discover.js

     

    데이터 처음 받아올때와 로드모어 버튼으로 더 받아올때를 나누기 위해서 firstload를 인자로 넘긴다.

    (처음 데이터 받아오기 전에만 firstLoad false 이다. )

    import axios from 'axios'
    import React, { useEffect, useState } from 'react'
    import { useDispatch, useSelector } from 'react-redux'
    import Loading from '../component/Loading'
    import PostThumb from '../component/PostThumb'
    import { getDiscoverPost } from '../_actions/postActions'
    import { GET_DISCOVER_POST_RESET, GET_DISCOVER_POST_UPDATE } from '../_constants/postConstants'
    
    function Discover({props}) {
        const userLogin = useSelector(state => state.userLogin)
        const {userInfo} = userLogin
    
        if(!userInfo){
            props.history.push('/login')
        }
    
        const [skip, setSkip] = useState(0)
        const [limit, setLimit] = useState(3)
        const [load, setLoad] = useState(false)
        const [page, setPage] = useState(2)
        const [posts, setPosts] = useState([])
    
        const dispatch = useDispatch();    
    
        const discoverpost = useSelector(state => state.discoverpost)
        const {discoverpost:discoveredpost, loading, result, firstLoad} = discoverpost;
    
        useEffect(() => {
            if(!firstLoad){
                dispatch(getDiscoverPost())
            }
        },[dispatch, firstLoad,page, limit])
    
        const onLoadMore = async() =>{
            setLoad(true)
            const res = await axios.get(`/api/discover?num=${page*9}`,{
            headers:{authorization:`Bearer ${userInfo.token}`},
            })
    
            dispatch({
            type:GET_DISCOVER_POST_UPDATE,
            payload:res.data
            })
            
            setPage(page+1)
            setLoad(false)
    
        }
    
    
    
    
        return (
            <div>
                {
                    
                    loading
                    ? <Loading></Loading>
                    : discoveredpost && <PostThumb posts={discoveredpost} result={discoveredpost} />
    
                }
                {
                    load && <Loading></Loading>
                }
    
                {
                    !loading &&
                    result<9*(page-1) ? '':
                        <button className="btn btn-dark mx-auto d-block" onClick={onLoadMore}>LoadMore</button>
    
                }
            </div>
    
        )
    }
    
    export default Discover

     

     

    postThumb.js

    (여기서 ? 안써주면 왜 지랄나는지 모를...ㅠ)

     

    (댓글로 알려주셔서 내용을 추가한다!🙌)

    여기서 ?는 optional chaning 연산자로 null이나 undefined와 같은 값에 대한 예외처리를 자동화 해주는 것으로 객체가 존재하지 않으면 undefined를 반환한다. 

    (참고 사이트)

    https://lunuy.tistory.com/m/4

     

    자바스크립트 물음표, 물음표 두개 연산자의 정체

    이게 무슨 문법인가 해서 구글 검색창에 자바스크립트 물음표를 쳐봤는데, 물음표 두개라는 검색어가 바로 뜨더라. 그런데도 검색결과를 보면 죄다 삼항 연산자에 대한 이야기들만 늘어놓고 있

    lunuy.tistory.com

     

     

    import React from 'react'
    import {Link} from 'react-router-dom'
    
    function PostThumb({posts, result}) {
    
        if(result ===0) return <h2 className="text-center text-danger">No Post</h2>
    
        return (
            <div className="post_thumb">
                {
                    posts.map(post=>(
                        <Link key={post._id} to={`/post/${post._id}`}>
                            <div className="post_thumb_display">
                                {
                                    // console.log(post.images[0])
                                    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">{post.likes.length}</i>
                                    <i className="far fa-comment">{post.comments.length}</i>
                                </div>
                            </div>
                        </Link>
                    ))
                }
            </div>
        )
    }
    
    export default PostThumb

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.