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