:login 은 변수임 여기에 깃허브 아이디가 들어감
GithubContext.jsx
user 객체를 추가 및 프로바이더 값에 추가
테스트한것 처럼 아래의
//한명 유저 찾기
const getUsers = async (login) => {
setLoading(); //로딩상태 true
const response = await fetch(`${GITHUB_URL}/users?${login}`, {
headers: {
Authorization: `token ${GITHUB_TOKEN}`,
},
});
//만약 찾지 못했을 경우(404) -> notfound 페이지로 이동
//결과가 있을 경우 dispatch로 user를 업데이트한다
if (response.status === 404) {
window.loading = "/notfound";
} else {
const { data } = await response.json();
dispatch({
type: "GET_USER",
payload: data,
});
}
};
GithubReducer.js에 GET_USER추가
const githubReducer = (state, action) => {
switch (action.type) {
case "GET_USERS":
return {
...state,
users: action.payload,
loading: false,
};
case "GET_USER":
return {
...state,
user: action.payload,
loading: false,
};
case "SET_LOADING":
return {
...state,
loading: true,
};
case "CLEAR_USERS":
return {
...state,
users: [],
};
default:
return state;
}
};
export default githubReducer;
GithubContext.jsx
User.jsx
특정 유저 프로파일 보기 클릭했을 경우
주소(path)에 로그인아이디가 파라미터로 넘어가며 그것을 콘솔로 찍어봤다.
import React, { useContext, useEffect } from "react";
import GithubContext from "../../context/github/GithubContext";
import { useParams } from "react-router-dom";
const User = () => {
const { user, getUser } = useContext(GithubContext);
//path파라미터로 유저 아이디가 넘어옴
const params = useParams();
console.log(params);
//최초 1회 실행
useEffect(() => {
getUser(params.login);
}, []);
return (
<h3>
{user.login}, {user.id}
</h3>
);
};
export default User;
프로파일을 클릭했을 때 데이터가 잘 넘어가는지 테스트함
User.jsx 꾸미기
import React, { useContext, useEffect } from "react";
import GithubContext from "../../context/github/GithubContext";
import { Link, useParams } from "react-router-dom";
import Spinner from "../layout/Spinner";
const User = () => {
const { user, getUser, loading } = useContext(GithubContext);
//path파라미터로 유저 아이디가 넘어옴
const params = useParams();
//console.log(params);
//최초 1회 실행
useEffect(() => {
getUser(params.login);
}, []);
//유저 데이터 목록
const {
name,
type,
avatar_url,
location,
bio,
blog,
twitter_username,
login,
html_url,
followers,
following,
public_repos,
hireable,
} = user;
if (loading) {
return <Spinner />;
} else {
return (
<>
<div className="w-full mx-auto lg:w-10/12">
<div className="mb-4">
<Link to="/" className="btn btn-ghost">
Back To Search
</Link>
</div>
<div className="grid grid-cols-1 xl:grid-cols-3 lg:grid-cols-3 md:grid-cols-3 mb-8 md:gap-8">
<div className="custom-card-image mb-6 md:mb-0">
<div className="rounded-lg shadow-xl card image-full">
<figure>
<img src={avatar_url} alt="" />
</figure>
<div className="card-body justify-end">
<h2 className="card-title mb-0">{name}</h2>
<p className="flex-grow-0">{login}</p>
</div>
</div>
</div>
<div className="col-span-2">
<div className="mb-6">
<h1 className="text-3xl card-title">
{name}
<div className="ml-2 mr-1 badge badge-success">{type}</div>
{hireable && (
<div className="mx-1 badge badge-info">Hireable</div>
)}
</h1>
<p>{bio}</p>
<div className="mt-4 card-actions">
<a
href={html_url}
target="_blank"
rel="noreferrer"
className="btn btn-outline"
>
Visit Github Profile
</a>
</div>
</div>
</div>
</div>
</div>
</>
);
}
};
export default User;
<div className='w-full rounded-lg shadow-md bg-base-100 stats'>
{location && (
<div className='stat'>
<div className='stat-title text-md'>Location</div>
<div className='text-lg stat-value'>{location}</div>
</div>
)}
{blog && (
<div className='stat'>
<div className='stat-title text-md'>Website</div>
<div className='text-lg stat-value'>
<a href={blog} target='_blank' rel='noreferrer'>
{blog}
</a>
</div>
</div>
)}
{twitter_username && (
<div className='stat'>
<div className='stat-title text-md'>Twitter</div>
<div className='text-lg stat-value'>
<a href={`https://twitter.com/${twitter_username}`} target='_blank' rel='noreferrer'>
{twitter_username}
</a>
</div>
</div>
)}
</div>
마지막 div태그 위에 붙여넣기
location과 website가 있으면 아래와 같이 나오고
없으면 안나온다.
import { FaCodepen, FaUserFriends, FaUsers } from 'react-icons/fa';
이것도 마지막 div태그위에 붙여넣기함
<div className='w-full py-5 mb-6 rounded-lg shadow-md bg-base-100 stats'>
<div className='grid grid-cols-1 md:grid-cols-3'>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaUsers className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Followers</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{followers}
</div>
</div>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaUserFriends className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Following</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{following}
</div>
</div>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaCodepen className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Public Repos</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{public_repos}
</div>
</div>
</div>
</div>
나는 location과 website가없어서 이렇게 나옴
그리고 유저 id로 해당 유저의 repository를 가져오도록 함
postman으로 테스트해봄
id는 변수로 들어가서 : 가들어감
GithubContext.jsx에 repos추가한다.
프로바이더에도 전달하고
//유저의 레포 가져오기
const getUserRepos = async (login) => {
setLoading(); //로딩상태 true
const response = await fetch(`${GITHUB_URL}/users/${login}/repos`, {
headers: {
Authorization: `token ${GITHUB_TOKEN}`,
},
});
const data = await response.json();
dispatch({
type: "GET_REPOS",
payload: data,
});
};
GithubReducer.js에서 GET_PEPO 추가한다.
GithubContext.jsx에서 프로바이더에 getUserRepos도 전달
User.jsx에서 마지막div 위에 RepoList 컴포넌트 추가
RepoList가 잘 추가되었는지 확인한다.
User.jsx에서 컨텍스트에서 repos를 가져온다.
RepoList컴포넌트에 repos props전달
GithubContext.jsx
User.jsx에서 useEffect()에 추가
RepoList.jsx에서
props로 넘어온 repos 배열을 map 반복문으로 하나씩 출력한다.
import React from "react";
const RepoList = ({ repos }) => {
// console.log(repos);
return (
<div className="rounded-lg shadow-lg card bg-base-100">
<div className="card-body">
<h2 className="text-3xl my-4 font-bold card-title">
최근 리포 10개 표시
</h2>
{repos.map((repo) => (
<h3 key={repo.id}>{repo.name}</h3>
))}
</div>
</div>
);
};
export default RepoList;
그리고 각 리포의 내용을 담을 RepoItem.jsx 컴포넌트를 생성한다.
그리고 RepoList.jsx에서 h3태그 -> RepoItem.jsx 로 교체한다.
props로 repo를 전달한다.
RepoItem.jsx
import React from "react";
import { FaEye, FaInfo, FaLink, FaStar, FaUtensils } from "react-icons/fa";
import PropTypes from "prop-types";
const RepoItem = ({ repo }) => {
const {
name,
description,
html_url,
forks,
open_issues,
watchers_count,
stargazers_count,
} = repo;
return (
<div className="mb-2 rounded-md card bg-base-200 hover:bg-base-300">
<div className="card-body">
<h3 className="mb-2 text-xl font-semibold">
<a href={html_url}>
<FaLink className="inline mr-1" /> {name}
</a>
</h3>
<p className="mb-3">{description}</p>
<div>
<div className="mr-2 badge badge-info badge-lg">
<FaEye className="mr-2" /> {watchers_count}
</div>
<div className="mr-2 badge badge-success badge-lg">
<FaStar className="mr-2" /> {stargazers_count}
</div>
<div className="mr-2 badge badge-error badge-lg">
<FaInfo className="mr-2" /> {open_issues}
</div>
<div className="mr-2 badge badge-warning badge-lg">
<FaUtensils className="mr-2" /> {forks}
</div>
</div>
</div>
</div>
);
};
RepoItem.propTypes = {
repo: PropTypes.object.isRequired,
};
export default RepoItem;
참고로 아까도 비슷하게 {} 안에 여러 항목들이 있고,각 항목들을 분해를 하는거임
repo안의 name 객체
repo안에 description 객체
이런식으로 따로 분리를 하는데 그 경우에는 { }안에 작성을 하면됨 .
테스트하기
'FRONTEND > React' 카테고리의 다른 글
[마이머니앱] 프로젝트 시작/로그인 / 가입하기 페이지 생성 (1) | 2023.12.04 |
---|---|
[React-BookStore] 알라딘API 검색 기능 추가 (1) | 2023.12.03 |
[깃허브 앱] Alert 컨텍스트 (0) | 2023.12.01 |
[깃허브 앱] Reducer 사용하여 유저 검색, 클리어 기능 (0) | 2023.11.30 |
[깃허브 앱] 깃허브 API 로 유저 검색 (0) | 2023.11.30 |