-
#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; };
끝