follow, unfollow (1)

김종민·2022년 5월 10일
0

insta-reactJS

목록 보기
26/27

들어가기
front부분에서 user를 follow, unfollow하는 부분,
일단은 cache부분은 생략하고 useMuataion, useQuery 부분만 마무리 한다.
Profile에서 follow, unFollow할 수 있게 구성한다.

1. src/pages/Profile.js

-styled부분에 대한 설명은 일단 생략함



import { gql, useApolloClient, useMutation, useQuery } from '@apollo/client'
import { useParams } from 'react-router-dom'
import styled from 'styled-components'
import Button from '../components/auth/Button'
import { FatText } from '../components/shared'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faHeart, faComment } from '@fortawesome/free-solid-svg-icons'
import useUser from '../hooks/useUser'

const SEE_PROFILE_QUERY = gql`
  query seeProfile($username: String!) {
    seeProfile(username: $username) {
      username
      bio
      avatar
      photos {
        id
        file
        likes
        commentNumber
        isLiked
      }
      totalFollowing
      totalFollowers
      isMe
      isFollowing
    }
  }
`
///1. seeProfile Query만듬

const FOLLOW_USER_MUTATION = gql`
  mutation followUser($username: String!) {
    followUser(username: $username) {
      ok
    }
  }
`
///2. followUser Mutation 만듬.

const UNFOLLOWER_USER_MUTATION = gql`
  mutation unfollowUser($username: String!) {
    unfollowUser(username: $username) {
      ok
    }
  }
`
///3. unfollowUser 만듬.

const Header = styled.div`
  display: flex;
  margin-top: 40px;
`
const Avatar = styled.img`
  margin-left: 50px;
  height: 160px;
  width: 160px;
  border-radius: 50%;
  margin-right: 150px;
  background-color: #2c2c2c;
`

const Column = styled.div``
const Username = styled.h3`
  font-size: 28px;
  font-weight: 400;
`
const Row = styled.div`
  margin-bottom: 20px;
  font-size: 16px;
  display: flex;
  align-items: center;
`
const List = styled.ul`
  display: flex;
`
const Item = styled.li`
  margin-right: 20px;
`
const Value = styled(FatText)`
  font-size: 18px;
`
const Name = styled(FatText)`
  font-size: 18px;
`

const Grid = styled.div`
  display: grid;
  grid-auto-rows: 290px;   ///한 줄의 길이
  grid-template-columns: repeat(3, 1fr); ///한줄에 3개씩 배치
  gap: 20px;  //사진 사이의  gap
  margin: 50px 30px;
`

const Photo = styled.div`
  background-size: cover;
  position: relative;  ///사진위에 heart, comment 띄울려면 position: relative
  background-image: url(${(props) => props.bg});
`
const Icons = styled.div`
  position: absolute; ///사진위에 heart, comment 띄울려면 position: absolute
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  color: white;
  opacity: 0.2;
  &:hover {
    opacity: 0.8;
  }
`
const Icon = styled.span`
  font-size: 18px;
  display: flex;
  align-items: center;
  margin: 0px 5px;
  svg {
    font-size: 14px;
    margin-right: 5px;
  } ///svg는 아이콘을 설정해줌...
`
const ProfileBtn = styled(Button).attrs({
  as: 'span', ///Buttion을 상속받음, attrs는 속성을 span으로 바꾸어 줌
})`
  margin-left: 20px;
  margin-right: 0px;
  cursor: pointer;
`

function Profile() {
  const { username } = useParams()
  const { data: userData } = useUser()
  const client = useApolloClient()
  const { data, loading } = useQuery(SEE_PROFILE_QUERY, {
    variables: {
      username,
    },
  })
  ///4. useQuery(SEE_PROFILE_QUERY)만들어서 data를 받아옴.
  ///variables는 useParams로 받은 username
  
  const upfollowUserUpdate = (cache, result) => {
    const {
      data: {
        unfollowUser: { ok },
      },
    } = result
    if (!ok) {
      return
    }
    cache.modify({
      id: `User:${username}`,
      fields: {
        isFollowing(prev) {
          return false
        },
        totalFollowers(prev) {
          return prev - 1
        },
      },
    })
    const { me } = userData
    cache.modify({
      id: `User:${me.username}`,
      fields: {
        totalFollowing(prev) {
          return prev - 1
        },
      },
    })
  }

  const [unfollowUserMutation] = useMutation(UNFOLLOWER_USER_MUTATION, {
    variables: {
      username,
    },
    update: upfollowUserUpdate,
    //refetchQueries: [
        //{query: SEE_PROFILE_QUERY, variables:{username}}
        //  ,{query:SEE_PROFILE_QUERY, variables:{username:userData?.me?.username}}]
  })
  ///5. useMutation(UNGOLLOW_USER_MUTAION)을 만듬.
  ///variables는 useParams로 받은 username
  ///cache를 다룰 update 부분은 다음 POST 에서 다룸.
  ///refetchQueries부분은 참고만 하기 바람.username과, me.username 두개를 
  ///refetch해야함.
  ///loggedInUser인 userData?.me?.username는 위에서 useUser()훅을 
  ///이용해서 data:userData를 받아온다.
  
  const followUserCompleted = (data) => {
    const {
      followUser: { ok },
    } = data
    if (!ok) {
      return
    }
    const { cache } = client
    cache.modify({
      id: `User:${username}`,
      fields: {
        isFollowing(prev) {
          return true
        },
        totalFollowers(prev) {
          return prev + 1
        },
      },
    })
    const { me } = userData;
    cache.modify({
      id: `User:${me.username}`,
      fields: {
        totalFollowing(prev) {
          return prev + 1
        },
      },
    })
  }
  const [followUserMutation] = useMutation(FOLLOW_USER_MUTATION, {
    variables: {
      username,
    },
    onCompleted: followUserCompleted,
    //refetchQueries: [{query: SEE_PROFILE_QUERY, variables:{username}}]
  })
  ///6.useMutation(FOLLOW_USER_MUTAITION)을 만든다.
  ///variables는 useParams로 받은 username이다.
  ///onCompleted는 다음 POST에서 설명예정
  ///refetchQueries를 사용할려면, unfollowUser처럼, 2개를 refetch해야함.

  const getButton = (seeProfile) => {
    const { isMe, isFollowing } = seeProfile
    if (isMe) {
      return <ProfileBtn>Edit Profile</ProfileBtn>
    }
    if (isFollowing) {
      return <ProfileBtn onClick={unfollowUserMutation}>Unfollow</ProfileBtn>
    } else {
      return <ProfileBtn onClick={followUserMutation}>Follow</ProfileBtn>
    }
  }
  ///7. Profile.js 페이지에서 username 옆에 
  ///user가 누구인지, isFollowing의 유무에따라
  ///EditProfile, fUnfollow, Follow 3개중에 하나가 보이게 하는
  ///getButton을 만듬.
  ///isMe, isFollowing은 seeProfile Query로 받아옴.
  
  return (
    <div>
      <Header>
        <Avatar src={data?.seeProfile?.avatar} />
        <Column>
          <Row>
            <Username>{data?.seeProfile?.username}</Username>
            {data?.seeProfile ? getButton(data.seeProfile) : null}
            ///getButton 함수에 (data.seeProfile)을 보내주어서
            ///getButton에서 isMe, isFollowing을 사용할 수 있게 함.
            
          </Row>
          <Row>
            <List>
              <Item>
                <span>
                  <Value>{data?.seeProfile?.totalFollowers} followers</Value>
                </span>
              </Item>
              <Item>
                <span>
                  <Value>{data?.seeProfile?.totalFollowing} following</Value>
                </span>
              </Item>
            </List>
          </Row>
          <Row>{data?.seeProfile?.bio}</Row>
        </Column>
      </Header>

      <Grid>
      	////seeProfile Query로 받아온 data의 사진을 뿌려줌.
        ///styled에서 Grid, Icons, Icon, Photo는
        ///중요하니 꼭 다시 확인해 볼것!!!!!!!
      
        {data?.seeProfile?.photos.map((photo) => (
          <Photo key={photo.id} bg={photo.file}>
            <Icons>
              <Icon>
                <FontAwesomeIcon icon={faHeart} />
                {photo.likes}
              </Icon>
              <Icon>
                <FontAwesomeIcon icon={faComment} />
                {photo.commentNumber}
              </Icon>
            </Icons>
          </Photo>
        ))}
      </Grid>
    </div>
  )
}

export default Profile
profile
코딩하는초딩쌤

0개의 댓글