인스타그램클론(노마드코더강의)/#9 Frontend: Profile
#9 Frontend: Profile
김마드
2020. 4. 21. 15:05
#9.0 Profile Screen part One~ #9.1 Two
Profile 부분을 만들어보자.
Routes.js 파일에서 url 주소/:username을 입력 하면 Profile Route파일로 이동하게 된다.
해당 /:username은 params에 담기게 된다. 이게 무슨말인지 이어서 보자.
>Routes.js
const LoggedInRoutes = () => (
<Switch>
<Route exact path="/" component={Feed} />
<Route path="/explore" component={Explore} />
<Route path="/search" component={Search} />
<Route path="/:username" component={Profile} />
</Switch>
);
>ProfileContainer.js
import React from "react";
import { gql } from "apollo-boost";
import { withRouter } from "react-router-dom";
import { useQuery } from "react-apollo-hooks";
import ProfilePresenter from "./ProfilePresenter";
const GET_USER = gql`
query seeUser($username: String!) {
seeUser(username: $username) {
id
avatar
username
fullName
isFollowing
isSelf
bio
followingCount
followersCount
postsCount
posts {
id
files {
url
}
likeCount
commentCount
}
}
}
`;
export default withRouter(
({
match: {
params: { username },
},
}) => {
const { data, loading } = useQuery(GET_USER, { variables: { username } });
return <ProfilePresenter loading={loading} data={data} />;
}
);
gql를 통해 seeUser값을 받아온다. 여기서 특징은, withRouter를 사용하여 params에 있는 값을 가지고 올 수 있다. 여기서 username은 위 Routes.js에서 정의한 username값이다.
>ProfilePresenter.js
import React from "react";
import styled from "styled-components";
import { Helmet } from "react-helmet";
import Loader from "../../Components/Loader";
import Avatar from "../../Components/Avatar";
import FatText from "../../Components/FatText";
import FollowButton from "../../Components/FollowButton";
import SquarePost from "../../Components/SquarePost";
const Wrapper = styled.div`
min-height: 100vh;
`;
const Header = styled.header`
display: flex;
align-items: center;
justify-content: space-around;
width: 80%;
margin: 0 auto;
margin-bottom: 40px;
`;
const HeaderColumn = styled.div``;
const UsernameRow = styled.div`
display: flex;
align-items: center;
`;
const Username = styled.span`
font-size: 26px;
display: block;
`;
const Counts = styled.ul`
display: flex;
margin: 15px 0px;
`;
const Count = styled.li`
font-size: 16px;
&:not(:last-child) {
margin-right: 10px;
}
`;
const FullName = styled(FatText)`
font-size: 16px;
`;
const Bio = styled.p`
margin: 10px 0px;
`;
const Posts = styled.div`
display: grid;
grid-template-columns: repeat(4, 200px);
grid-template-rows: 200px;
grid-auto-rows: 200px;
`;
export default ({ loading, data }) => {
if (loading === true) {
return (
<Wrapper>
<Loader />
</Wrapper>
);
} else if (!loading && data && data.seeUser) {
console.log(data);
const {
seeUser: {
id,
avatar,
username,
fullName,
isFollowing,
isSelf,
bio,
followingCount,
followersCount,
postsCount,
posts,
},
} = data;
return (
<Wrapper>
<Helmet>
<title>{username} | Prismagram</title>
</Helmet>
<Header>
<HeaderColumn>
<Avatar size="lg" url={avatar} />
</HeaderColumn>
<HeaderColumn>
<UsernameRow>
<Username>{username}</Username>{" "}
{!isSelf && <FollowButton isFollowing={isFollowing} id={id} />}
</UsernameRow>
<Counts>
<Count>
<FatText text={String(postsCount)} /> posts
</Count>
<Count>
<FatText text={String(followersCount)} /> followers
</Count>
<Count>
<FatText text={String(followingCount)} /> following
</Count>
</Counts>
<FullName text={fullName} />
<Bio>{bio}</Bio>
</HeaderColumn>
</Header>
<Posts>
{posts &&
posts.map((post) => (
<SquarePost
key={post.id}
likeCount={post.likeCount}
commentCount={post.commentCount}
file={post.files[0]}
/>
))}
</Posts>
</Wrapper>
);
}
return null;
};
#9.2 Log Out and Conclusions
로그아웃 기능을 만들어보자. (Profile안에)
>ProfileContainer.js
import React from "react";
import { gql } from "apollo-boost";
import withRouter from "react-router-dom/withRouter";
import { useQuery, useMutation } from "react-apollo-hooks";
import ProfilePresenter from "./ProfilePresenter";
const GET_USER = gql`
query seeUser($username: String!) {
seeUser(username: $username) {
id
avatar
username
fullName
isFollowing
isSelf
bio
followingCount
followersCount
postsCount
posts {
id
files {
url
}
likeCount
commentCount
}
}
}
`;
const LOG_OUT = gql`
mutation logUserOut {
logUserOut @client
}
`;
export default withRouter(
({
match: {
params: { username },
},
}) => {
const { data, loading } = useQuery(GET_USER, { variables: { username } });
const [logOut] = useMutation(LOG_OUT);
return <ProfilePresenter loading={loading} logOut={logOut} data={data} />;
}
);
로그아웃에 대한 mutation 을 만들어 두었다. (버튼 클릭 시 onClick 이벤트로 발동)
이는 localState를 이용한 것이다. (logInUser와 같이)
>ProfilePresenter.js
import React from "react";
import styled from "styled-components";
import { Helmet } from "react-helmet";
import Loader from "../../Components/Loader";
import Avatar from "../../Components/Avatar";
import FatText from "../../Components/FatText";
import FollowButton from "../../Components/FollowButton";
import SquarePost from "../../Components/SquarePost";
import Button from "../../Components/Button";
const Wrapper = styled.div`
min-height: 100vh;
`;
const Header = styled.header`
display: flex;
align-items: center;
justify-content: space-around;
width: 80%;
margin: 0 auto;
margin-bottom: 40px;
`;
const HeaderColumn = styled.div``;
const UsernameRow = styled.div`
display: flex;
align-items: center;
`;
const Username = styled.span`
font-size: 26px;
display: block;
`;
const Counts = styled.ul`
display: flex;
margin: 15px 0px;
`;
const Count = styled.li`
font-size: 16px;
&:not(:last-child) {
margin-right: 10px;
}
`;
const FullName = styled(FatText)`
font-size: 16px;
`;
const Bio = styled.p`
margin: 10px 0px;
`;
const Posts = styled.div`
display: grid;
grid-template-columns: repeat(4, 200px);
grid-template-rows: 200px;
grid-auto-rows: 200px;
`;
export default ({ loading, data, logOut }) => {
if (loading === true) {
return (
<Wrapper>
<Loader />
</Wrapper>
);
} else if (!loading && data && data.seeUser) {
const {
seeUser: {
id,
avatar,
username,
fullName,
isFollowing,
isSelf,
bio,
followingCount,
followersCount,
postsCount,
posts,
},
} = data;
return (
<Wrapper>
<Helmet>
<title>{username} | Prismagram</title>
</Helmet>
<Header>
<HeaderColumn>
<Avatar size="lg" url={avatar} />
</HeaderColumn>
<HeaderColumn>
<UsernameRow>
<Username>{username}</Username>{" "}
{isSelf ? (
<Button onClick={logOut} text="Log Out" />
) : (
<FollowButton isFollowing={isFollowing} id={id} />
)}
</UsernameRow>
<Counts>
<Count>
<FatText text={String(postsCount)} /> posts
</Count>
<Count>
<FatText text={String(followersCount)} /> followers
</Count>
<Count>
<FatText text={String(followingCount)} /> following
</Count>
</Counts>
<FullName text={fullName} />
<Bio>{bio}</Bio>
</HeaderColumn>
</Header>
<Posts>
{posts &&
posts.map((post) => (
<SquarePost
key={post.id}
likeCount={post.likeCount}
commentCount={post.commentCount}
file={post.files[0]}
/>
))}
</Posts>
</Wrapper>
);
}
return null;
};
끝