Створення сучасного новинного хабу за допомогою React та TypeScript: всебічний посібник

pic

Привіт! 👋 Сьогодні я покажу тобі, як створити NewsHub, сучасний агрегатор новин, використовуючи React, TypeScript і Tailwind CSS. Це ідеальний проєкт як для початківців, так і для досвідчених розробників, які хочуть створити готовий до продакшн новинний додаток з такими функціями, як темна тема, поширення статей і додавання до закладок.

Вступ

NewsHub — це адаптивний веб-додаток, який дозволяє користувачам:

  • Переглядати новинні статті за категорією.
  • Шукати конкретні новини.
  • Додавати улюблені статті до закладок для легкого доступу.
  • Ділитися статтями в соціальних мережах.
  • Перемикатися між світлим і темним режимами.

Повний вихідний код цього проєкту можна знайти на GitHub.

Технології

Ми будемо використовувати наступні технології:

  • React 18 для створення інтерфейсу користувача.
  • TypeScript для статичної типізації та підвищення якості коду.
  • Tailwind CSS для швидкого та гнучкого стилізування.
  • Vite як сучасний і швидкий інструмент для збірки.
  • Lucide React для іконок.
  • GNews API для отримання новинних даних.

Початок роботи

Спочатку налаштуємо структуру нашого проєкту. Ми використаємо Vite з шаблоном React і TypeScript:

npm create vite@latest news-hub -- --template react-ts  
cd news-hub  
npm install

Структура проєкту

Ось модульна структура нашого проєкту:

src/  
 ├── components/  
 ├── hooks/  
 ├── services/  
 ├── types/  
 ├── App.tsx  
 └── main.tsx

Реалізація основних функцій

Тут я поясню основні функції додатку. Щоб слідувати за прикладом, клонуй репозиторій Github.

1. Визначення типів статей

Почнемо з визначення інтерфейсів TypeScript, щоб забезпечити типову безпеку (в файлі src/types/index.ts):

export interface Article {  
 id: string;  
 title: string;  
 description: string;  
 source: string;  
 category: string;  
 url: string;  
 imageUrl?: string;  
 publishedAt: string;  
}  

export type Category =  
 | 'all'  
 | 'world'  
 | 'nation'  
 | 'business'  
 | 'technology'  
 | 'entertainment'  
 | 'sports'  
 | 'science'  
 | 'health';

Цей фрагмент коду служить як шаблон для визначення структури даних, які використовуються в додатку NewsHub. Ось що кожна частина робить:

A. Інтерфейс Article

Цей інтерфейс визначає форму об'єкта новинної статті. Кожна стаття містить:

  • id (string): Унікальний ідентифікатор статті.
  • title (string): Заголовок статті.
  • description (string): Короткий опис змісту статті.
  • source (string): Назва джерела новин або видавця.
  • category (string): Категорія статті, наприклад, спорт або технології.
  • url (string): Посилання на повний текст статті.
  • imageUrl (необов'язкове значення string): Посилання на зображення, яке супроводжує статтю.
  • publishedAt (string): Дата та час публікації статті.

Це гарантує, що всі статті відповідають єдиній структурі, що полегшує їх обробку та відображення в додатку.

B. Тип Category

Це об'єднаний тип, який визначає можливі категорії новинних статей:

  • Включає такі категорії, як 'world', 'business', 'entertainment' тощо.
  • 'all' — це спеціальна категорія для отримання статей з усіх тем.

Це дозволяє додатку фільтрувати або організовувати статті відповідно до цих заздалегідь визначених категорій, покращуючи досвід перегляду.

Чому це важливо

  • Типова безпека: Використовуючи TypeScript, ви можете виявити помилки під час розробки, якщо дані не відповідають визначеній структурі.
  • Підтримуваність: Чітке визначення типів робить код зрозумілішим, легшим для читання та підтримки.
  • Гнучкість: З добре визначеною структурою додавати нові функції, такі як фільтрація за категорією або валідація вхідних даних, стає простіше.

Ця основа є критично важливою для створення надійного та зручного новинного додатку!
Отримання новин з GNews API

Сервіс newsApi.ts обробляє API-запити для отримання новинних статей:

const API_KEY = 'your_api_key';  
const BASE_URL = 'https://gnews.io/api/v4';  

export async function fetchNews(category: string = 'all', query: string = '') {  
 const endpoint = query ? 'search' : 'top-headlines';  
 const params = new URLSearchParams({  
 apikey: API_KEY,  
 lang: 'en',  
 country: 'us',  
 max: '10',  
 ...(query ? { q: query } : {}),  
 ...(category !== 'all' ? { topic: category } : {}),  
 });  

 const response = await fetch(`${BASE_URL}/${endpoint}?${params}`);  
 const data = await response.json();  

 return {  
 articles: data.articles.map((article: any, index: number) => ({  
 id: String(index + 1),  
 title: article.title || 'Untitled',  
 description: article.description || 'No description available',  
 source: article.source?.name || 'Unknown Source',  
 category: category === 'all' ? 'general' : category,  
 url: article.url || '#',  
 imageUrl: article.image,  
 publishedAt: article.publishedAt || new Date().toISOString(),  
 })),  
 };  
}

Цей фрагмент коду визначає функцію fetchNews, яка отримує новинні статті з GNews API на основі категорій або пошукових запитів, заданих користувачем. Ось пояснення, що робить цей код:

A. Налаштування API:

  • Функція підключається до GNews API, використовуючи API-ключ (API_KEY) та базову URL-адресу (BASE_URL).

B. Вхідні параметри:

  • category: Визначає тип новин (наприклад, 'business', 'technology'). За замовчуванням встановлено 'all' для загальних новин.
  • query: Пошуковий запит для фільтрації статей. Якщо він заданий, то будуть отримані статті, що відповідають цьому запиту.

C. Вибір ендпоінту:

  • Якщо заданий query, використовується ендпоінт search для конкретного пошуку. Інакше за замовчуванням використовується top-headlines для загальних новин.

D. Параметри запиту:

  • Мова (lang) встановлена на англійську.
  • Країна (country) встановлена на США.
  • Максимальна кількість статей — 10.
  • Додаткові фільтри для запиту та категорії додаються, якщо це необхідно.

E. Отримання та парсинг даних:

  • Функція відправляє запит до API, чекає на відповідь і парсить отримані дані у форматі JSON.

F. Форматований вихід:

  • Отримані статті перетворюються в єдиний формат, що включає:
    • Унікальний ID.
    • Заголовок, опис та назву джерела (за замовчуванням використовується заповнювач, якщо вони відсутні).
    • Категорія та дата публікації.
    • URL та зображення для статті.

G. Повертається:

  • Структурований об'єкт, що містить відформатовані статті, що дозволяє легко відображати їх у додатку.

Ця функція є важливою частиною вашого додатку, забезпечуючи динамічний доступ до нових статей, керованих користувачем!
Створення компонента картки статті

Компонент ArticleCard відображає окремі новинні статті:

import React from 'react';  
import { Bookmark, Share2 } from 'lucide-react';  
import type { Article } from '../types';  

interface ArticleCardProps {  
 article: Article;  
 isBookmarked: boolean;  
 onBookmark: (id: string) => void;  
 onShare: (article: Article) => void;  
}  

export function ArticleCard({ article, isBookmarked, onBookmark, onShare }: ArticleCardProps) {  
 return (  

    {article.imageUrl && (        )}    
    {article.title}    

 {article.description}  

    Read more        
 onBookmark(article.id)}>             onShare(article)}>            
    );   } ```  

Цей компонент `ArticleCard` використовується для відображення інформації про статтю у вигляді картки. Він приймає такі властивості:

- **article**: Об'єкт, що містить деталі статті, такі як заголовок, опис, URL та зображення.
- **isBookmarked**: Логічне значення, яке вказує, чи є стаття в закладках.
- **onBookmark**: Функція, яка обробляє додавання статті до закладок, коли користувач натискає на іконку закладки.
- **onShare**: Функція, яка обробляє поширення статті, коли користувач натискає на іконку спільного доступу.

## Як це працює:

- **Зображення статті**: Якщо у статті є зображення, воно буде відображене в верхній частині картки.
- **Заголовок та опис**: Заголовок статті та короткий опис відображаються в картці. Опис обрізається, щоб вмістити лише два рядки.
- **Посилання на повну статтю**: Надається посилання на повну статтю, яке відкривається в новій вкладці.
- **Кнопки закладки та поширення**:
  - Кнопка закладки дозволяє користувачу додавати або видаляти статтю з закладок. Якщо стаття додана в закладки, кнопка підсвічується.
  - Кнопка поширення дозволяє користувачу поділитися статтею, використовуючи надану функцію.

Картка має чистий та адаптивний дизайн з ефектами при наведенні та підтримує світлий/темний режим, який адаптується відповідно до уподобань користувача щодо теми.

## 4. Темний режим з Tailwind CSS

Ми використовуємо кастомний хук для збереження налаштувань темного режиму в `localStorage` (в `src/hooks/useLocalStorage.ts`):

import { useState, useEffect } from 'react';

export function useLocalStorage(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});

useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.error(error);
}
}, [key, storedValue]);

return [storedValue, setStoredValue] as const;
}
```

Хук useLocalStorage є кастомним хуком для React, який допомагає вам керувати станом, одночасно зберігаючи та отримуючи дані з localStorage браузера. Він працює подібно до хука useState, але з додатковою функціональністю збереження даних у localStorage, щоб дані залишались доступними навіть після оновлення сторінки або повторного відкриття браузера.

Як це працює:

A.
Початковий стан:

  • Коли хук використовується вперше, він перевіряє, чи існує вказаний key в localStorage. Якщо існує, збережене значення витягується та використовується як початковий стан. Якщо ж у localStorage немає значення, використовується передане initialValue.
  • Якщо виникає помилка при зчитуванні з localStorage, хук виводить помилку в консоль і повертає initialValue.

B. Оновлення стану:

  • Коли стан (storedValue) оновлюється за допомогою функції setStoredValue, це значення також зберігається в localStorage, забезпечуючи збереження даних навіть після перезавантаження сторінки чи сесії.
  • Якщо виникає помилка при записі в localStorage, помилка виводиться в консоль.

C. Повернуте значення:

  • Хук повертає масив, перший елемент якого — це поточне значення, збережене в localStorage, а другий — функція (setStoredValue), яка може бути використана для оновлення збереженого значення.

Розширені функції

1. Пошук з дебаунсом

Для оптимізації API запитів ми використовуємо дебаунс для вводу пошуку:

import { useState, useEffect } from 'react';  

export function useDebounce(value: T, delay: number): T {  
 const [debouncedValue, setDebouncedValue] = useState(value);  
 useEffect(() => {  
 const timer = setTimeout(() => {  
 setDebouncedValue(value);  
 }, delay);  
 return () => clearTimeout(timer);  
 }, [value, delay]);  
 return debouncedValue;  
}

2. Модальне вікно для поширення в соціальних мережах

Модальне вікно для поширення дозволяє користувачам ділитися статтями в різних соціальних мережах:

export function ShareModal({ article, onClose }: { article: Article; onClose: () => void; }) {  
 const shareUrl = article.url;  
 const shareText = `Check out this article: ${article.title}`;  

 const shareLinks = {  
 x: `https://twitter.com/intent/tweet?url=${encodeURIComponent(shareUrl)}&text=${encodeURIComponent(shareText)}`,  
 linkedin: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(shareUrl)}`,  
 };  
 // Render the modal content...  
}

Висновок

NewsHub демонструє, як побудувати сучасний новинний додаток за допомогою React і TypeScript. Основні висновки:

  • Використання TypeScript для забезпечення типобезпеки.
  • Реалізація темного режиму за допомогою Tailwind CSS.
  • Ефективне управління станом за допомогою React hooks.
  • Створення багаторазових компонентів для масштабованого коду.
  • Безперешкодна інтеграція з API.
  • Покращення досвіду користувача через соціальний обмін та закладки.

Щоб почати:

  1. Отримайте свій API-ключ від GNews.
  2. Замініть API-ключ в newsApi.ts.
  3. Встановіть залежності за допомогою npm install.
  4. Запустіть сервер розробки за допомогою npm run dev.

Якщо ви знайшли цей посібник корисним, поділіться ним з іншими, хто вивчає React і TypeScript, та поставте кілька лайків. Якщо у вас є питання або відгуки, залишайте їх у коментарях нижче. Щасливого кодування!

Перекладено з: Building a Modern News Hub with React and TypeScript: A Comprehensive Guide

Leave a Reply

Your email address will not be published. Required fields are marked *