Рубрики
Без рубрики

Как построить Hacker News Clone, используя реагирование

В этом уроке мы построим клону News Mini Hacker в реакции. Мы будем использовать синтаксис реактивных крюков для создания этого приложения. Поэтому, если вы новичок, чтобы реагировать крюки, проверьте мое введение, чтобы отреагировать статью крюки, чтобы узнать основы крючков. Так что давайте начнем. Вступление

Автор оригинала: Yogesh Chavan.

В этом руководстве мы построим Мини Хакеров Новости клон в реакции.

Мы будем использовать синтаксис реактивных крюков для создания этого приложения. Так что если вы новичок, чтобы реагировать крюки, проверьте мой Введение в реактивный крюк Статья для изучения оснований крючков.

Так что давайте начнем.

Введение в API

Мы будем использовать API Hackernews из этот URL Отказ

API, чтобы получить лучшие истории, используйте этот URL: https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty

API Чтобы получить новые истории, используйте этот URL: https://hacker-news.firebaseio.com/v0/newstories.json?print=pretty

API, чтобы получить лучшие истории, используйте этот URL: https://hacker-news.firebaseio.com/v0/beststories.json?print=pretty

Каждый из вышеупомянутых историй API возвращает только массив идентификаторов, представляющих историю.

Итак, чтобы получить детали этой конкретной истории, нам нужно сделать другой вызов API.

API Чтобы получить подробности истории, используйте этот URL: https://hacker-news.firebaseio.com/v0/item/story_id.json?print=pretty

Например: https://hacker-news.firebaseio.com/v0/item/26061935.json?print=pretty

Как настроить проект

Создайте новый проект, используя Create-React-App :

npx create-react-app hackernews-clone-react-app

Как только проект создан, удалите все файлы из SRC Папка и создать index.js и styles.cscss Файлы внутри SRC папка. Также создать Компоненты , крючки , Маршрутизатор , Utils Папки внутри SRC папка.

Установите необходимые зависимости, такие как это:

yarn add axios@0.21.0 bootstrap@4.6.0 node-sass@4.14.1 react-bootstrap@1.4.0 react-router-dom@5.2.0

Открыть styles.cscss и добавьте содержимое от здесь внутри него.

Мы будем использовать синтаксис SCSS для записи CSS. Так что если вы новичок в SCSS, проверьте Моя статья здесь для введения к этому.

Как создать начальные страницы

Создать новый файл Header.js внутри Компоненты Папка со следующим содержанием:

import React from 'react';
import { NavLink } from 'react-router-dom';

const Header = () => {
  return (
    
      

Hacker News Clone

Top Stories Latest Stories Best Stories
); }; export default Header;

В этом файле мы добавили меню навигации, чтобы увидеть различные типы историй. Каждая ссылка добавила класс Активный Отказ Поэтому, когда мы нажимаем на эту ссылку, она будет выделена, указывая, какой маршрут мы находимся.

Создать новый файл Homepage.js внутри Компоненты Папка со следующим содержанием:

import React from 'react';

const HomePage = () => {
  return Home Page;
};

export default HomePage;

Создать новый файл Pagenotfound.js внутри Компоненты Папка со следующим содержанием:

import React from 'react';
import { Link } from 'react-router-dom';

const PageNotFound = () => {
  return (
    

Page Not found. Go to Home

); }; export default PageNotFound;

Создать новый файл Arenter.js внутри Маршрутизатор Папка со следующим содержанием:

import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from '../components/Header';
import HomePage from '../components/HomePage';
import PageNotFound from '../components/PageNotFound';

const AppRouter = () => {
  return (
    
      
); }; export default AppRouter;

В этом файле, изначально, мы добавили два маршрута для маршрутизации – один для домашней страницы, а другой для неверных маршрутов.

Если вы новичок, чтобы реагировать на маршрутизатор, проверьте мой бесплатный Введение в React Router курс.

Теперь откройте SRC/index.js Файл и добавьте следующее содержимое внутри него:

import React from 'react';
import ReactDOM from 'react-dom';
import AppRouter from './router/AppRouter';
import 'bootstrap/dist/css/bootstrap.min.css';
import './styles.scss';

ReactDOM.render(, document.getElementById('root'));

Теперь запустите приложение, запустив Пряжа начать команда И вы увидите следующий экран:

Интеграция API

Теперь внутри Utils Папка создать новый файл под названием constants.js Со следующим контентом:

export const BASE_API_URL = 'https://hacker-news.firebaseio.com/v0';

Создайте другой файл с именем apis.js внутри Utils Папка со следующим содержанием:

import axios from 'axios';
import { BASE_API_URL } from './constants';

const getStory = async (id) => {
  try {
    const story = await axios.get(`${BASE_API_URL}/item/${id}.json`);
    return story;
  } catch (error) {
    console.log('Error while getting a story.');
  }
};

export const getStories = async (type) => {
  try {
    const { data: storyIds } = await axios.get(
      `${BASE_API_URL}/${type}stories.json`
    );
    const stories = await Promise.all(storyIds.slice(0, 30).map(getStory));
    return stories;
  } catch (error) {
    console.log('Error while getting list of stories.');
  }
};

В этом файле для Getstories функция, которую мы проходим тип истории, которую мы хотим ( верх , Новый или Лучший ). Тогда мы делаем вызов API к соответствующему .json URL предоставлен в начале этой статьи.

Обратите внимание, что мы объявили функцию как async. Таким образом, мы можем использовать Ждите Ключевое слово, чтобы вызвать API и дождитесь появления ответа.

const { data: storyIds } = await axios.get(
  `${BASE_API_URL}/${type}stories.json`
);

Как Axios Библиотека всегда возвращает результат в .дата Свойство ответа, мы вынимаем это свойство и переименовать его на Сказки Потому что API возвращает массив идентификаторов историй.

Здесь мы используем синтаксис разрезания ES6 для переименования данные недвижимость на рассказы . Это позволяет легко понять, что Сказки содержит, а не назвать его данные Отказ

Обратите внимание, что вышеуказанный код такой же, как указанный ниже код:

const response = await axios.get(
  `${BASE_API_URL}/${type}stories.json`
);
const storyIds = response.data;

Поскольку мы получаем массив идентификаторов истории, вместо того, чтобы сделать отдельные вызовы API для каждого ID а потом жду предыдущего, чтобы закончить мы используем Обещание. Все Способ сделать вызовы API одновременно для всех идентификаторов истории.

const stories = await Promise.all(
  storyIds.slice(0, 30).map((storyId) => getStory(storyId))
);

Здесь мы используем метод ломтики массива, чтобы взять только первые 30 идентификаторов историй, поэтому данные будут загружаться быстрее.

Затем мы используем метод MAP MAP, чтобы позвонить в getstory Функция, чтобы сделать API вызов отдельным элементом истории, передавая СТРОИТЕЛЬ к этому.

Как и в функции карты, мы просто возьмем историю и передаем ее на getstory функция. Мы можем упростить его в следующий код:

const stories = await Promise.all(storyIds.slice(0, 30).map(getStory));

Итак, СТРОИТЕЛЬ будет автоматически передан на getstory функция.

Внутри getstory Функция, мы используем шаблон ES6 литерального синтаксиса ES6 для создания динамического URL на основе прошедшего идентификатора для создания вызова API.

И как только у нас есть истории, мы вернемся от Getstories функция.

Как создать данные Fetcher

Создать новый файл datafetcher.js внутри крючки Папка со следующим содержанием:

import { useState, useEffect } from 'react';
import { getStories } from '../utils/apis';

const useDataFetcher = (type) => {
  const [stories, setStories] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsLoading(true);
    getStories(type)
      .then((stories) => {
        setStories(stories);
        setIsLoading(false);
      })
      .catch(() => {
        setIsLoading(false);
      });
  }, [type]);

  return { isLoading, stories };
};

export default useDataFetcher;

В этом файле мы объявили пользовательский крюк Uificatafetcher который принимает тип истории в качестве параметра и называет Getstories Функция определена в apis.js Файл внутри Useffect крюк.

Мы добавили две переменные состояния здесь, используя Уместите крючок, а именно Истории а также загружает Отказ Прежде чем сделать вызов API, мы установили загружает Государство в правда Отказ Как только мы получим полный ответ, мы установили его на ложь Отказ

Мы также устанавливаем загружает Государство в ложь Внутри блока Catch так, если есть ошибка, загрузчик будет скрыт.

Как только ответ получен, мы устанавливаем Истории Массив с ответом от API, и мы возвращаем загружает и Истории от крючка в объекте. Это означает, что любой компонент, использующий этот крюк, сможет получить обновленное значение этих состояний.

Кроме того, обратите внимание, что мы добавили Тип как зависимость от Useffect Крюк в качестве второго параметра внутри массива. Итак, когда мы нажимаем на меню навигации (для Top , Последние или Лучший Истории), тип изменится и это Useffect Крюк снова запустится, чтобы сделать вызов API, чтобы получить истории, связанные с этим типом.

Если вы помните, внутри apis.js Файл Getstories Функция объявляется как async. Так что это всегда будет вернуть обещание. Поэтому мы добавили .then Обработчик к Getstories Функция, чтобы получить фактические данные из ответа внутри Useffect крючок внутри datafetcher.js файл, как это:

getStories(type)
      .then((stories) => {
      ...

Как отображать данные в интерфейсе UI

Теперь создайте новый файл под названием Showsstory.js внутри Компоненты Папка со следующим содержанием:

import React from 'react';
import Story from './Story';
import useDataFetcher from '../hooks/dataFetcher';

const ShowStories = (props) => {
  const { type } = props.match.params;
  const { isLoading, stories } = useDataFetcher(type);

  return (
    
      {isLoading ? (
        

Loading...

) : ( {stories.map(({ data: story }) => ( ))} )}
); }; export default ShowStories;

В этом файле мы используем Uificatafetcher Пользовательский крючок внутри компонента. На основе загружает Флаг, мы либо отображаем Загрузка Сообщение или список историй с использованием метода карты массива для каждой отдельной истории.

Создать новый файл Story.js внутри Компоненты Папка со следующим содержанием:

import React from 'react';

const Link = ({ url, title }) => (
  
    {title}
  
);

const Story = ({ story: { id, by, title, kids, time, url } }) => {
  return (
    
by{' '} | {new Date(time * 1000).toLocaleDateString('en-US', { hour: 'numeric', minute: 'numeric' })} | 0 ? kids.length : 0} comments`} />
); }; export default Story;

В этом файле мы отображаем отдельную историю.

Для определения Ссылка Компонент, мы используем функцию стрелки ES6 Shorthand Shreadax неявного возврата.

Так что ниже код:

const Link = ({ url, title }) => (
  
    {title}
  
);

так же, как этот код:

const Link = ({ url, title }) => {
  return (
    
     {title}
    
  );
}

В функции стрелки, если есть однострочное оператор, то мы можем пропустить курсовые кронштейны и вернуть ключевое слово.

Так что ниже код:

const add = (a,b) => a + b;

так же, как этот код:

const add = (a,b) => {
  return a + b;
}

Но сделать JSX выглядеть аккуратно и как однострочное заявление, мы добавляем дополнительные круглые кронштейны при определении Ссылка составная часть.

Далее для История Компонент, мы определили это так:

const Story = ({ story: { id, by, title, kids, time, url } }) => {
  // some code
}

Здесь мы используем синтаксис деструктурирования ES6 для получения свойств истории объекта, который был передан из Showsties составная часть.

Таким образом, приведенный выше код такой же, как указанный ниже код:

const Story = (props) => {
  const { id, by, title, kids, time, url } = props.story;
  // some code
}

что такое же, как указанный ниже код:

const Story = ({ story }) => {
  const { id, by, title, kids, time, url } = story;
  // some code
}

В ответ API мы получаем время истории в считанные секунды. Так в История Компонент, мы умножимся на 1000, чтобы преобразовать его в миллисекунды, чтобы мы могли отобразить правильную дату в правильном формате, используя JavaScript Толокаледательестр Метод:

{new Date(time * 1000).toLocaleDateString('en-US', {
  hour: 'numeric',
  minute: 'numeric'
})}

Теперь откройте Arenter.js Файл и добавьте еще один маршрут для Showsties компонент до PageNotfowound Маршрут.


  
  
  

Кроме того, добавьте импорт для Showsties Компонент наверху:

import ShowStories from '../components/ShowStories';

Теперь перезапустите приложение, запустив Пряжа начать Команда и проверить приложение.

Как видите, приложение загружает лучшие, последние и лучшие истории от API Hackernews.

Как обрабатывать динамическое перенаправление

Если вы помните, мы добавили Главная страница Компонент, поэтому мы можем отобразить что-то, когда нагрузки приложений. Но теперь нам на самом деле не нужны Главная страница Компонент, потому что мы можем показать страницу верхних историй, когда нагрузки приложений.

Так что откройте Arenter.js Файл и изменить первые два маршрута из следующего кода:



К настоящему коду:

 } exact={true} />
 {
    const { type } = match.params;
    if (!['top', 'new', 'best'].includes(type)) {
       return ;
    }
    return ;
  }}
/>

В первом маршруте, когда мы загружаем приложение, посетив http://localhost: 3000/ мы перенаправляем пользователя к /топ маршрут.

 } exact={true} />

Здесь мы используем рисунок рендеринга. Поэтому вместо того, чтобы обеспечить компонент, мы используем опоры с именем оказывать Где мы можем писать код компонента непосредственно внутри функции.

Знать, почему мы используем оказывать вместо Компонент опоры и какая проблема это решает, проверьте мой бесплатный Введение в React Router курс.

Далее мы добавили /: Тип маршрут:

 {
    const { type } = match.params;
    if (!['top', 'new', 'best'].includes(type)) {
      return ;
    }
    return ;
  }}
/>

Здесь, если маршрут совпадает с /топ или /новый или /Лучший Затем мы показываем пользователю Showsties составная часть. Если пользователь вводит некоторое недопустимое значение для маршрута, как /что-то Мы снова перенаправляем пользователю к /топ Маршрут, который сделает Showsties компонент с верх истории..

Мы используем массив ES7 включает в себя Метод в вышеуказанном коде внутри приведенного выше условия.

По умолчанию маршрутизатор RACT проходит некоторые реквизиты для каждого компонента, упомянутой в <Маршрут/> Отказ Один из них – соответствие Итак, roppsmatch.params будет содержать фактическое пропущенное значение для Тип Отказ

Поэтому, когда мы доступаем к http://localhost: 3000/топ , roppsmatch.params будет содержать значение верх Отказ Когда мы доступаем к http://localhost: 3000/new , roppsmatch.params будет содержать значение новый и так далее.

Для функции Render Prop мы используем деструктурию, чтобы получить Матч Свойство объекта реквизита с помощью следующего синтаксиса:

render={({ match }) => {
}

который такой же, как:

render={(props) => {
 const { match } = props;
}

Кроме того, не забудьте импортировать Перенаправить Компонент из React-Router-DOM пакет в верхней части Arenter.js файл.

import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';

Теперь откройте Showsstory.js Файл и изменить код ниже:

const ShowStories = (props) => {
  const { type } = props.match.params;
  const { isLoading, stories } = useDataFetcher(type);

К настоящему коду:

const ShowStories = ({ type }) => {
  const { isLoading, stories } = useDataFetcher(type ? type : 'top');

Вот, мы проезжаем Тип опоры пропущены из Rechnouter Компонент к Uificatafetcher Пользовательский крючок. Это сделает правильный тип данных, основанных на Тип прошедший.

Как добавить наложение загрузки

Теперь мы добавили код перенаправления для автоматического перенаправления на /топ Маршрут на загрузке приложений. Неверный маршрут также перенаправляет к /топ маршрут.

Но когда данные загружаются, мы показываем простое загрузочное сообщение. Хотя данные загружаются, пользователь может нажать на другую ссылку, чтобы сделать дополнительные запросы на сервер, который не является хорошим.

Итак, давайте добавим сообщение по загрузке с наложением на экран, чтобы пользователь не сможет нажать в любом месте, пока данные загружаются.

Создать новый файл Loader.js. внутри Компоненты Папка со следующим содержанием:

import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';

const Loader = (props) => {
  const [node] = useState(document.createElement('div'));
  const loader = document.querySelector('#loader');

  useEffect(() => {
    loader.appendChild(node).classList.add('message');
  }, [loader, node]);

  useEffect(() => {
    if (props.show) {
      loader.classList.remove('hide');
      document.body.classList.add('loader-open');
    } else {
      loader.classList.add('hide');
      document.body.classList.remove('loader-open');
    }
  }, [loader, props.show]);

  return ReactDOM.createPortal(props.children, node);
};

export default Loader;

Теперь открыть Public/index.html Файл и рядом с Div с ID корень Добавьте еще один div с ID погрузчик , нравится:

Reactom.CreatePortal Метод, который мы использовали в Loader.js. вставит погрузчик внутри Div с ID погрузчик Так что это будет вне нашего Реагировать Применение Дом иерархии. Это означает, что мы можем использовать его, чтобы обеспечить наложение для всего нашего приложения. Это основная причина использования React Portal для создания погрузчика.

Так что даже если мы включаем Погрузчик Компонент в Showsstory.js Файл, он будет отображаться снаружи всех Divs (но внутри Div с ID Loader ).

В Loader.js Файл, мы впервые создали div, где мы добавим сообщение погрузчика

const [node] = useState(document.createElement('div'));

Затем мы добавляем сообщение Класс к этому div и, наконец, добавить, что Div в Loader Div добавлен в index.html :

document.querySelector('#loader').appendChild(node).classList.add('message');

и основываясь на Показать опоры пропущены из Showsties Компонент, мы добавим или удалите Спрятать класс. Тогда, наконец, мы сделаем Погрузчик Компонент, используя это:

ReactDOM.createPortal(props.children, node);

Затем мы добавляем или удалив Loader-Open Класс из теги тела страницы, которая отключит или включает прокрутку страницы:

document.body.classList.add('loader-open');
document.body.classList.remove('loader-open');

Данные, которые мы передаем между открытием и закрываем Погрузчик тег внутри Showsties Компонент будет доступен внутри roppsshildren. . Таким образом, мы можем отобразить простое загрузочное сообщение или мы можем включить изображение, которое будет отображаться как загрузчик.

Теперь давайте будем использовать этот компонент.

Открыть Showsstory.js Файл и замените его содержимое со следующим содержимым:

import React from 'react';
import Story from './Story';
import useDataFetcher from '../hooks/dataFetcher';
import Loader from './Loader';

const ShowStories = (props) => {
  const { type } = props.match.params;
  const { isLoading, stories } = useDataFetcher(type);

  return (
    
      Loading...
      
        {stories.map(({ data: story }) => (
          
        ))}
      
    
  );
};

export default ShowStories;

Здесь мы используем компонент погрузчика, передавая его по шоу.

Loading...

Теперь, если вы проверяете приложение, вы увидите загрузку наложения:

Итак, теперь пользователь не может нажать на любую ссылку, пока данные загружаются, что приятное улучшение.

Для каждой истории мы показываем автор и общие комментарии как гиперссылки. Нажав на них, отвечает нам на веб-сайт Hackernews, чтобы показать соответствующие детали, как вы можете видеть в подведенном ниже GIF.

Точки закрытия

Мы закончили построить функциональность приложения.

Вы можете найти полный исходный код GitHub здесь и живая демонстрация здесь Отказ

Чтобы пополнить ваши навыки, вы можете улучшить приложение, добавив дополнительные функции, такие как:

  • Добавить функциональность Pagination для загрузки следующих 30 записей для каждой страницы
  • Создайте отдельную страницу в приложении для отображения комментариев с помощью Hacker News API Отказ При нажатии на нажатие, комментарии считают ссылку вместо перенаправления пользователя на веб-сайт Hackernews

Спасибо за прочтение!

Хотите построить более удивительные проекты? Проверь их здесь Отказ

Кроме того, вы можете проверить мой бесплатный Введение в React Router Курс для изучения React Router с нуля.

Хотите узнать все функции ES6 + подробно, включая пусть и const, обещания, различные методы обещания, массив и деструктурирование объектов, функции стрелки, Async/ждут, импорт и экспорт и намного больше?

Проверьте мой Овладение современным JavaScript книга. Эта книга охватывает все предпосылки для реагирования на обучение и помогает вам стать лучше на JavaScript и реагировать.

Не забудьте подписаться на мой Еженедельная рассылка Чтобы получить удивительные советы, трюки, статьи и скидки непосредственно в вашем почтовом ящике.

Оригинал: “https://www.freecodecamp.org/news/how-to-build-a-hacker-news-clone-using-react/”