Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Мы ожидаем, что Вы исправите синтаксические ошибки, сделаете перехват возможных исключений и улучшите читаемость кода.
- // А так же, напишите кастомный хук useThrottle и используете его там где это нужно. - не пригодилось, реализация через pending
- // Желательно использование React.memo и React.useCallback там где это имеет смысл.
- // Будет большим плюсом, если Вы сможете закэшировать получение случайного пользователя.
- // Укажите правильные типы.
- // По возможности пришлите Ваш вариант в https://codesandbox.io
- import React, { useState, useCallback } from "react";
- import type {MouseEvent} from "react";
- const URL = "https://jsonplaceholder.typicode.com/users";
- function getRandomInt(min : number, max : number) {
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
- interface Company {
- bs: string;
- catchPhrase: string;
- name: string;
- }
- interface User {
- id: number;
- email: string;
- name: string;
- phone: string;
- username: string;
- website: string;
- company: Company;
- address: string
- }
- enum FetchStatus {
- pending = 'pending',
- success = 'success',
- error = 'error',
- null = 'null' // первый запрос
- }
- interface WithPendingProps {
- status : FetchStatus,
- }
- // Если подход с ожиданием ответа будет применятся по проекту - будет неплохо вынести этот функционал отдельно
- function withPending<T>(WrappedComponent : any) {
- return function (props : T & WithPendingProps) {
- const {status} = props;
- if(status === FetchStatus.pending) {
- return <div>
- <p>Ожидайте идет получение данных</p>
- </div>
- }
- if(status === FetchStatus.error) {
- return <div>
- <p>Одна ошибка и ты ошибся !</p>
- </div>
- }
- return <>
- <WrappedComponent {...props} />
- </>
- }
- }
- interface IUserInfoProps {
- user: User | null;
- }
- // Нет смысла мемоизировать - часто меняется
- function UserInfo({ user }: IUserInfoProps) {
- if(user === null) {
- return <></>
- }
- return <>
- <td>{user.name}</td>
- <td>{user.phone}</td>
- </>
- }
- // Инициализируем компонент и интерфейс под оберткой
- const UserInfoWithStatus = withPending<IUserInfoProps>(UserInfo)
- const App = () => {
- // Текущий пользователь, по умолчанию пусто
- const [item, setItem] = useState<User | null>(null);
- // Можно усложнить и добавить время жизни Кэша
- const [cache] = useState<Map<number, User>>(new Map());
- // Текущее состояние запроса, запрещаем отправлять еще 1 пока первый не вернулся текущий запрос
- const [isPending, setIsPending] = useState<FetchStatus>(FetchStatus.null);
- // Запрос на получение нового пользователя, с проверкой Кэша
- const receiveRandomUser = useCallback(async () => {
- // Есть пользователи с 1-10. Специально сделаем шанс ошибки - чтобы проверить работу ERROR статуса
- // TODO: Можно предусмотреть чтобы не совпадал с последним, но не критично
- const id = getRandomInt(0, 11);
- // Проверяем есть ли данные в Cache
- if(cache.has(id)) {
- setItem(cache.get(id) as User);
- setIsPending(FetchStatus.success);
- return;
- }
- // Получаем пользователя
- setIsPending(FetchStatus.pending);
- fetch(`${URL}/${id}`)
- .then(res => {
- if(!res.ok) {
- throw new Error('bad request');
- }
- return res.json() as Promise<User>
- })
- .then(_user => {
- setIsPending(FetchStatus.success);
- cache.set(id, _user)
- setItem(_user);
- })
- .catch(err => {
- console.log(`catch`);
- // Возможно стоит получать и отображать ошибку в теле компонента, уточнить у ПМ-а =)
- setIsPending(FetchStatus.error)
- })
- }, [cache, setItem]);
- const handleButtonClick = useCallback((event: MouseEvent<HTMLButtonElement>) => {
- event.stopPropagation();
- receiveRandomUser();
- }, [receiveRandomUser]);
- // Throttle не нужен из-за наличия статуса запроса
- // Таблица вынесена отдельна, чтобы меньше HTML элементов перерисовывалось
- // Честно говоря абсолютно не уверен что добился чего хотел, но для такого компонента задуманный рефактор избыточен
- return (
- <div>
- <h1>Get a random user</h1>
- <button
- type="button"
- onClick={handleButtonClick}
- disabled={isPending === FetchStatus.pending}
- >
- get random user
- </button>
- <table>
- <thead>
- <tr>
- <th>Username</th>
- <th>Phone number</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <UserInfoWithStatus user={item} status={isPending}/>
- </tr>
- </tbody>
- </table>
- </div>
- );
- }
- export default App;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement