Doriți să vă îmbunătățiți abilitățile de dezvoltare React? Construiește-ți propria versiune de Hacker News cu ajutorul acestui ghid.

Hacker News este un site web popular printre antreprenori și dezvoltatori. Prezintă conținut axat pe informatică și antreprenoriat.

Aspectul simplu al Hacker News poate fi potrivit pentru anumite persoane. Cu toate acestea, dacă doriți o versiune mai atrăgătoare și personalizată, puteți utiliza API-uri utile pentru a vă crea propria experiență personalizată Hacker News. De asemenea, construirea clonei Hacker News vă poate ajuta să vă consolidați abilitățile de React.

Configurarea serverului de proiect și dezvoltare

Codul folosit în acest proiect este disponibil în a Depozitul GitHub și este gratuit pentru utilizare sub licența MIT.

Pentru stil, copiați conținutul index.css fișier din depozit și inserați-le în al dvs index.css fişier. Dacă doriți să aruncați o privire la o versiune live a acestui proiect, puteți verifica aceasta demonstrație.

Pachetele necesare pentru acest proiect includ:

instagram viewer
  • React Router pentru a gestiona rutarea în Aplicație de o singură pagină (SPA).
  • HTMLReactParser pentru analiza HTML returnat de Interfață de programare a aplicațiilor (API).
  • MomentJS pentru gestionarea datelor returnate de API.

Deschideți terminalul și rulați:

yarn create vite

De asemenea, puteți utiliza Node Package Manager (NPM) daca il preferi in defavoarea firelor. Comanda de mai sus ar trebui să folosească instrumentul de compilare Vite pentru a schelă un proiect de bază. Denumiți-vă proiectul și atunci când vi se solicită cadrul, alegeți Reacţiona și setați varianta la JavaScript.

Acum CD în folderul proiectului și instalați pachetele menționate mai devreme, rulând următoarele comenzi în terminal:

yarn adăugați html-react-parser
yarn add react-router-dom
adaugă fire moment
fire dev

După instalarea tuturor pachetelor și pornirea serverului de dezvoltare, deschideți proiectul în orice editor de cod și creați trei foldere în src folder și anume: componente, cârlige, și pagini.

În componente folder, adăugați două fișiere Comentarii.jsx și Navbar.jsx. În cârlige folder, adăugați un fișier foloseșteFetch.jsx. Apoi în pagini folder, adăugați două fișiere ListPage.jsx și PostPage.jsx.

Ștergeți App.css fișier și înlocuiți conținutul fișierului main.jsx fișier cu următoarele:

import Reacţiona din'reacţiona'
import { BrowserRouter } din„react-router-dom”
import ReactDOM din„react-dom/client”
import App din„./App.jsx”
import„./index.css”

ReactDOM.createRoot(document.getElementById('rădăcină')).face(



</BrowserRouter>
</React.StrictMode>,
)

În App.jsx fișier, eliminați tot codul standard și modificați fișierul astfel încât să aveți doar componenta funcțională rămasă:

funcţieApp() {
întoarcere (
<>
</>
)
}

exportMod implicit App

Importă modulele necesare:

import { Rute, Rută } din„react-router-dom”
import ListPage din„./pages/ListPage”
import Bara de navigare din„./components/Navbar”
import PostPage din„./pages/PostPage”

În fragmentul React, adăugați Trasee componente cu trei Traseu componente copil cu căi: /, /:type, și /item/:id respectiv.


'/'
element={<> <Bara de navigare /><ListPage /></>}>
</Route>
'/:tip'
element={<> <Bara de navigare /><ListPage /></>}>
</Route>
'/ID-ul itemului'
element={}>
</Route>
</Routes>

Crearea useFetch Custom Hook

Acest proiect folosește două API-uri. Primul API este responsabil pentru preluarea listei de postări dintr-o anumită categorie (tip), în timp ce al doilea API este API-ul Algolia, care este responsabil pentru preluarea unei anumite postări și a acesteia comentarii.

Deschide foloseșteFetch.jsx fișier, definiți cârligul ca export implicit și importați fișierul useState și useEffect cârlige.

import { useState, useEffect } din"reacţiona";
exportMod implicitfuncţiefoloseșteFetch(tip, id) {

}

Definiți trei variabile de stare și anume: date, eroare, și Se încarcă, cu funcțiile lor de setter respective.

const [date, setData] = useState();
const [eroare, setError] = useState(fals);
const [încărcare, setLoading] = useState(Adevărat);

Apoi, adăugați a useEffect cârlig cu dependențele: id și tip.

useEffect(() => {
}, [id, tip])

Apoi, în funcția de apel invers, adăugați funcția fetchData() pentru a prelua datele de la API-urile corespunzătoare. Dacă parametrul trecut este tip, utilizați primul API. În caz contrar, utilizați al doilea API.

asincronfuncţiefetchData() {
lăsa răspuns, url, parametru;
dacă (tip) {
url = " https://node-hnapi.herokuapp.com/";
parametru = type.toLowerCase();
}
altfeldacă (id) {
url = " https://hn.algolia.com/api/v1/items/";
parametru = id.toLowerCase();
}
încerca {
răspuns = asteapta aduce(`${url}${parametru}`);
} captură (eroare) {
setError(Adevărat);
}

dacă (raspuns) dacă (răspuns.status !== 200) {
setError(Adevărat);
} altfel {
lăsa date = asteapta răspuns.json();
setLoading(fals);
setData (date);
}
}
fetchData();

În cele din urmă, returnați Se încarcă, eroare, și date variabilele de stare ca obiect.

întoarcere { încărcare, eroare, date };

Redarea listei de postări în funcție de categoria solicitată

Ori de câte ori utilizatorul navighează la / sau /:type, React ar trebui să redea ListPage componentă. Pentru a implementa această funcționalitate, importați mai întâi modulele necesare:

import { useNavigate, useParams } din"react-router-dom";
import foloseșteFetch din„../hooks/useFetch”;

Apoi, definiți componenta funcțională și apoi atribuiți parametrul dinamic, tip la tip variabil. Dacă parametrul dinamic nu este disponibil, setați tip variabilă la știri. Apoi, sunați la foloseșteFetch cârlig.

exportMod implicitfuncţieListPage() {
lăsa { type } = useParams();
const navigate = foloseșteNavigate();
dacă (!type) tip = "știri";
const { încărcare, eroare, date } = useFetch (tip, nul);
}

Apoi, returnați codul JSX corespunzător, în funcție de care dintre ele Se încarcă, eroare, sau date variabile este adevărată.

dacă (eroare) {
întoarcere<div>Ceva n-a mers bine!div>
}

dacă (Se încarcă) {
întoarcere<div>Se încarcădiv>
}

dacă (date) {
document.title = type.toUpperCase();
întoarcere<div>

„tip de listă”>{type}</div>
{data.map(articol =>
"articol">
"titlu articol"
onClick={() => navigare(`/item/${item.id}`)}>
{item.title}
</div>
{item.domain &&
"link-ul articolului"
onClick={() => deschide(`${item.url}`)}>
({item.domain})</span>}
</div>)}
</div>
</div>
}

Crearea componentei PostPage

Mai întâi, importați modulele și componentele corespunzătoare, apoi definiți componenta funcțională implicită, atribuiți id parametru dinamic la id variabilă și, apelați foloseșteFetch cârlig. Asigurați-vă că destructurați răspunsul.

import { Link, useParams } din"react-router-dom";
import analiza din„html-react-parser”;
import moment din"moment";
import Comentarii din„../components/Comentarii”;
import foloseșteFetch din„../hooks/useFetch”;

exportMod implicitfuncţiePostPage() {
const { id } = useParams();
const { încărcare, eroare, date } = useFetch(nul, id);
}

Și la fel ca și cu ListPage componentă, redați JSX-ul corespunzător pe baza stării următoarelor variabile: Se încarcă, eroare, și date.

dacă (eroare) {
întoarcere<div>Ceva n-a mers bine!div>
}

dacă (Se încarcă) {
întoarcere<div>Se încarcădiv>
}

dacă (date) {
document.title=data.title;
întoarcere<div>

"post-titlu">{data.title}</div>
"post-metadate">
{data.url &&
className="post-link">Vizitați site-ul web</Link>}
"post-autor">{data.author}</span>
"post-time">
{moment (data.created_at).fromNow()}
</span>
</div>
{data.text &&
"post-text">
{parse (date.text)}</div>}
"post-comentarii">
"comentarii-eticheta">Comentarii</div>

</div>
</div>
}

Importă analiza modulul și moment modul. Definiți componenta funcțională implicită Comentarii care ia în comentariiDate matrice ca suport, traversează matricele și redă a Nodul componentă pentru fiecare element.

import analiza din„html-react-parser”;
import moment din"moment";

exportMod implicitfuncţieComentarii({ comentariiDate }) {
întoarcere<>
{commentsData.map(comentariuDate =><NodulcomentariuDate={commentData}cheie={commentData.id}
/>)}
</>
}

Apoi, definiți Nodul componentă funcțională chiar sub Comentarii componentă. The Nodul componenta redă comentariul, metadatele și răspunsurile la fiecare comentariu (dacă există), redându-se recursiv.

funcţieNodul({ commentData }) {
întoarcere<divnumele clasei="cometariu">
{
commentData.text &&
<>
„metadate-comentarii”>
{commentData.author}</span>

{moment (commentData.created_at).fromNow()}
</span>
</div>
„text-comentare”
>
{parse (commentData.text)}</div>
</>
}
„comentare-răspunsuri”
>
{(commentData.children) &&
commentData.children.map(copil =>
)}
</div>
</div>
}

În blocul de cod de mai sus, analiza este responsabil pentru analizarea HTML-ului stocat în commentData.text, in timp ce moment este responsabil pentru analizarea timpului de comentariu și returnarea timpului relativ folosind de acum() metodă.

Crearea componentei Navbar

Deschide Navbar.jsx fișier și importați fișierul NavLink modul din reacţionează-router-dom modul. În cele din urmă, definiți componenta funcțională și returnați un părinte nav element cu cinci NavLink elemente care indică categoriile (sau tipurile) adecvate.

import { NavLink } din"react-router-dom"

exportMod implicitfuncţieBara de navigare() {
întoarcere<nav>
"/știri">Acasă</NavLink>
"/Cel mai bun">Cel mai bun</NavLink>
"/spectacol">Arată</NavLink>
"/cere">Intreaba</NavLink>
"/locuri de munca">Locuri de munca</NavLink>
</nav>
}

Felicitări! Tocmai ți-ai creat propriul client front-end pentru Hacker News.

Consolidează-ți abilitățile de reacție prin construirea aplicației de clonă

Crearea unei clone Hacker News cu React vă poate ajuta să vă consolidați abilitățile React și să vă ofere o aplicație practică pe o singură pagină la care să lucrați. Există multe moduri prin care poți duce lucrurile mai departe. De exemplu, puteți adăuga posibilitatea de a căuta postări și utilizatori în aplicație.

În loc să încerci să-ți construiești propriul router de la zero, este mai bine să folosești un instrument construit de profesioniști care sunt dedicați să faciliteze crearea de SPA-uri.