Skip to content

Instantly share code, notes, and snippets.

@techeverri
Last active May 9, 2021 15:34
Show Gist options
  • Save techeverri/8908dbbb14ee8655a9295b74a1c39e9d to your computer and use it in GitHub Desktop.
Save techeverri/8908dbbb14ee8655a9295b74a1c39e9d to your computer and use it in GitHub Desktop.
GitHub avatar search with React Hooks
const { useState, useEffect, useRef } = React;
const GITHUB_USERS_API_URL = "https://api.github.com/users";
const GITHUB_CLIENT_ID = "8b7993e07c6a5750c784";
const GITHUB_CLIENT_SECRET = "fd815b52e8b01fd07995f30ba54f3b799d9ef93e";
const USER_CACHE_MAX_SIZE = 5;
const useCache = (cacheMaxSize) => {
const { current: cache } = useRef(new Map());
const hasKey = (key) => cache.has(key);
const getValue = (key) => cache.get(key);
const updateCache = (key, value) => {
cache.set(key, value);
if (cache.size > cacheMaxSize) {
const oldestKey = Array.from(cache.keys()).shift();
cache.delete(oldestKey);
}
};
return { has: hasKey, get: getValue, set: updateCache };
};
const useGitHubUser = (username) => {
const [user, setUser] = useState({});
const userCache = useCache(USER_CACHE_MAX_SIZE);
useEffect(() => {
const fetchUser = async () => {
const headers = new Headers({
Authorization: `Basic ${btoa(
`${GITHUB_CLIENT_ID}:${GITHUB_CLIENT_SECRET}`
)}`,
});
const response = await fetch(`${GITHUB_USERS_API_URL}/${username}`, {
headers,
});
const data = await response.json();
userCache.set(username, data);
setUser(data);
};
if (userCache.has(username)) {
setUser(userCache.get(username));
} else {
fetchUser();
}
}, [username]);
return user;
};
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timeoutID = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timeoutID);
}, [value, delay]);
return debouncedValue;
};
const GitHubAvatar = () => {
const [username, setUsername] = useState("");
const debouncedUsername = useDebounce(username, 250);
const user = useGitHubUser(debouncedUsername);
return (
<>
<h1>React GitHub Avatar</h1>
<div>
<label htmlFor="username">Username: </label>
<input
name="username"
placeholder="e.g. torvalds"
value={username}
onChange={(event) => setUsername(event.target.value)}
/>
</div>
{user.id && (
<>
<br />
<figure>
<img
style={{ width: 200 }}
alt="User avatar"
src={user.avatar_url}
/>
<figcaption>
{user.name}
<br />
<a
href={`https://github.com/${user.login}`}
target="_blank"
>{`@${user.login}`}</a>
</figcaption>
</figure>
</>
)}
</>
);
};
ReactDOM.render(<GitHubAvatar />, document.getElementById("app"));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>GitHub Avatar</title>
</head>
<body>
<div id="app"></div>
<script
src="https://unpkg.com/[email protected]/umd/react.production.min.js"
crossorigin
></script>
<script
src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"
crossorigin
></script>
<script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
<script type="text/babel" src="app.js"></script>
</body>
</html>
@techeverri
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment