ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Social Media 만들기 - 8) follow, unfollow 기능 만들기
    NODE.JS 2021. 7. 10. 04:57

    프로필 창에 나오는 follow 버튼을 활성화 시키자. 

    profile.js

                {loading&& <Loading></Loading>}
                {error && <Alert variant="danger">{error}</Alert>}
                <div className="info">
                    <div className="info_container" key={user?._id}>
                        <Avatar src={user?.avatar} size="supper-avatar" />
                        <div className="info_content">
                            <div className="info_content_title">
                                <h2>{user?.username}</h2>
                                {
                                    user?._id === userInfo.user._id 
                                    ? <button className="btn btn-outline-info" onClick={()=>setOnEdit(true)}>Edit Profile</button>
                                    :   <FollowBtn user={user}/>
                                }
                            </div>

     

     

    component>FollowBtn.js

    import React, { useEffect, useState } from 'react'
    import { useDispatch, useSelector } from 'react-redux'
    import { followUserProfile, unfollowUserProfile } from '../_actions/profileActions'
    
    function FollowBtn({user}) {
    
        const [follow, setFollow] = useState(false)
    
        const userLogin = useSelector(state => state.userLogin)
        const {userInfo} =userLogin
        const dispatch = useDispatch()
    
        useEffect(() => {
            if(userInfo.user.following.find(x=>x._id ===userId)){setFollow(true)}
        }, [userInfo.user.following, userId])
    
        const handleFollow= async ()=>{
            setFollow(true)
            await dispatch(followUserProfile(user))
        }
    
        const handleUnfollow = async () =>{
            setFollow(false)
            await dispatch(unfollowUserProfile(user))
        }
    
        return (
            <>
            {
    
                follow
                ?<button className="btn btn-outline-danger" onClick={handleUnfollow} >UnFollow</button>
                :<button className="btn btn-outline-info"onClick={handleFollow} >Follow</button>
                
            }
            </>
        )
    }
    
    export default FollowBtn

     

     

    라우터를 만들어주자. 

    userRouter.patch('/:id/follow', auth, async(req, res)=>{
        try{
            // const user = await User.findOne(req.params.id)
            // const follower = user.followers.filter(x=>x._id===req.user._id)
            // if(follower.length>0) return res.status(500).json({msg: "You followed this user."})
            const user = await User.find({_id: req.params.id, 'followers':req.body._id})
            if(user.length > 0) return res.status(500).json({msg: "You followed this user."})
    
            
            const newUser = await User.findOneAndUpdate({_id: req.body._id}, {
                $push: {following: req.params.id}
            }, {new: true}).populate("followers following", "-password")
            
            await User.findOneAndUpdate({_id: req.params.id}, { 
                $push: {'followers':req.body}
            }, {new: true})
    
            res.send({
                user : newUser,
                token:generateToken(newUser)
            })
    
        } catch (err) {
            return res.status(500).json({msg: err.message})
        }
    })
    
    userRouter.patch('/:id/unfollow', auth, async(req, res)=>{
        try{
            
            const newUser = await User.findOneAndUpdate({_id: req.body._id}, {
                $pull: {following: req.params.id}
            }, {new: true}).populate("followers following", "-password")
    
            await User.findOneAndUpdate({_id:req.params.id}, {
                $pull:{'followers':req.body._id}
            }, {new:true})
    
            console.log(newUser)
    
            res.json({
                user:newUser,
                token:generateToken(newUser)
            })
    
        }catch(err){
            return res.status(500).json({message:err.message})
        }
    })

     

    여기서 그대로 following이나 follower로 넣으면 objectId 가 아니라고 해서 한참 해맸다. ㅠㅠ

     

    https://stackoverflow.com/questions/26453507/argument-passed-in-must-be-a-single-string-of-12-bytes

     

    Argument passed in must be a single String of 12 bytes

    mongoDB collection contains the following data db.stack.find() { "_id" : "8GieRu" } The _id is not single String of 12 bytes, As per the MongoDB document of [ObjectID][1], id (string) – Can be a...

    stackoverflow.com

    이걸 보고 따라해서 'following'이러한 식으로 하니까 작동했다. 

    4시간은 고민한 것 같은데 그래도 작동해서 아슬아슬하지만 다행이다. 

     

     

    profile.action

    export const followUserProfile = (user)=> async(dispatch, getState)=>{
    
        const {userLogin: {userInfo}} = getState()
        let newUser =  {...user, followers:[...user.followers, userInfo.user] }
    
        try{
            
            const {data} = await axios.patch(`/api/users/${user._id}/follow`,userInfo.user,{
                headers:{authorization:`Bearer ${userInfo?.token}`}
            } )
    
            dispatch({
                type:USER_FOLLOW_PROFILE,
                payload:newUser
            })
            dispatch({
                type:USER_LOGIN_SUCCESS,
                payload:data
            })
            dispatch({
                type:USER_UPDATE_PROFILE_SUCCESS,
                payload : data
            })
    
            
            localStorage.removeItem('userInfo')
            localStorage.setItem('userInfo',JSON.stringify(data))
    
        }catch(err){
            dispatch({
                type:ALERT,
                payload:{error:err.response && err.response.data.message? err.response.data.message : err.message}
    
            })
        }
    
    }
    
    export const unfollowUserProfile = (user)=> async(dispatch, getState)=>{
    
        const {userLogin: {userInfo}} = getState()
        let newUser =  {...user, followers:user.followers.filter(x=>x._id !==userInfo.user._id) }
    
        try{
            
            const {data} = await axios.patch(`/api/users/${user._id}/unfollow`,userInfo.user,{
                headers:{authorization:`Bearer ${userInfo?.token}`}
            } )
    
            dispatch({
                type:USER_UNFOLLOW_PROFILE,
                payload:newUser
            })
            dispatch({
                type:USER_LOGIN_SUCCESS,
                payload:data
            })
            
            dispatch({
                type:USER_UPDATE_PROFILE_SUCCESS,
                payload : data
            })
    
            localStorage.removeItem('userInfo')
            localStorage.setItem('userInfo',JSON.stringify(data))
    
        }catch(err){
            dispatch({
                type:ALERT,
                payload:{error:err.response && err.response.data.message? err.response.data.message : err.message}
    
            })
        }
    }

     

    profilReducer.js

    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}
            default:
                return state;
        }
    }

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.