Quer melhorar suas habilidades de desenvolvimento React? Crie sua própria versão do Hacker News com a ajuda deste guia.

Hacker News é um site popular entre empreendedores e desenvolvedores. Possui conteúdo focado em informática e empreendedorismo.

O layout simples do Hacker News pode atender a certos indivíduos. No entanto, se você deseja uma versão mais atraente e personalizada, pode utilizar APIs úteis para criar sua própria experiência personalizada do Hacker News. Além disso, construir o clone do Hacker News pode ajudá-lo a solidificar suas habilidades de React.

Configurando o Project and Development Server

O código utilizado neste projeto está disponível em um Repositório GitHub e é gratuito para você usar sob a licença do MIT.

Para estilizar, copie o conteúdo do index.css arquivo do repositório e colá-los em seu próprio index.css arquivo. Se você quiser dar uma olhada em uma versão ao vivo deste projeto, você pode conferir este demonstração.

Os pacotes necessários para este projeto incluem:

instagram viewer
  • React Router para lidar com o roteamento no Aplicativo de página única (SPA).
  • HTMLReactParser para analisar o HTML retornado pelo Interface de Programação de Aplicativos (API).
  • MomentJS para lidar com as datas retornadas pela API.

Abra o terminal e execute:

fio criar vite

Você também pode usar o Gerenciador de pacotes de nós (NPM) se você preferir sobre fios. O comando acima deve usar a ferramenta de construção Vite para estruturar um projeto básico. Nomeie seu projeto e, quando solicitado pela estrutura, escolha Reagir e defina a variante como JavaScript.

Agora cd na pasta do projeto e instale os pacotes mencionados anteriormente executando os seguintes comandos no terminal:

yarn add html-react-parser
yarn add react-router-dom
fios adicionam momento
desenvolvedor de fios

Após instalar todos os pacotes e iniciar o servidor de desenvolvimento, abra o projeto em qualquer editor de código e crie três pastas no origem pasta a saber: componentes, ganchos, e Páginas.

No componentes pasta, adicione dois arquivos Comentários.jsx e Navbar.jsx. No ganchos pasta, adicione um arquivo useFetch.jsx. Então no Páginas pasta, adicione dois arquivos ListPage.jsx e PostPage.jsx.

Excluir o App.css arquivo e substitua o conteúdo do main.jsx arquivo com o seguinte:

importar Reagir de'reagir'
importar { Navegador Roteador } de'react-router-dom'
importar ReactDOM de'react-dom/client'
importar Aplicativo de'./App.jsx'
importar'./index.css'

ReactDOM.createRoot(documento.getElementById('raiz')).render(



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

No App.jsx arquivo, remova todo o código clichê e modifique o arquivo de forma que você tenha apenas o componente funcional restante:

funçãoAplicativo() {
retornar (
<>
</>
)
}

exportarpadrão Aplicativo

Importe os módulos necessários:

importar { Rotas, Rota } de'react-router-dom'
importar ListPage de'./pages/ListPage'
importar barra de navegação de'./components/Navbar'
importar PostPage de'./pages/PostPage'

No fragmento React, adicione o Rotas componentes com três Rota componentes filhos com caminhos: /, /:type, e /item/:id respectivamente.


'/'
elemento={<> <barra de navegação /><ListPage /></>}>
</Route>
'/:tipo'
elemento={<> <barra de navegação /><ListPage /></>}>
</Route>
'/item/:id'
elemento={}>
</Route>
</Routes>

Criando o gancho personalizado useFetch

Este projeto usa duas APIs. A primeira API é responsável por buscar a lista de postagens em uma determinada categoria (tipo), enquanto a segunda API é a API Algolia que é responsável por buscar um determinado post e seu comentários.

Abra o useFetch.jsx arquivo, defina o gancho como uma exportação padrão e importe o useState e useEffect ganchos.

importar { useState, useEffect } de"reagir";
exportarpadrãofunçãouseFetch(tipo, id) {

}

Defina três variáveis ​​de estado, a saber: dados, erro, e carregando, com suas respectivas funções de configuração.

const [dados, setData] = useState();
const [erro, setError] = useState(falso);
const [carregando, setCarregando] = useState(verdadeiro);

Em seguida, adicione um useEffect hook com as dependências: eu ia e tipo.

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

Em seguida, na função de retorno de chamada, adicione a função buscarData() para buscar os dados das APIs apropriadas. Se o parâmetro passado for tipo, use a primeira API. Caso contrário, use a segunda API.

assíncronofunçãobuscar dados() {
deixar resposta, url, parâmetro;
se (tipo) {
URL = " https://node-hnapi.herokuapp.com/";
parâmetro = type.toLowerCase();
}
outrose (eu ia) {
URL = " https://hn.algolia.com/api/v1/items/";
parâmetro = id.toLowerCase();
}
tentar {
resposta = aguardam buscar(`${url}${parâmetro}`);
} pegar (erro) {
setError(verdadeiro);
}

se (resposta) se (resposta.status !== 200) {
setError(verdadeiro);
} outro {
deixar dados = aguardam resposta.json();
setCarregando(falso);
setData (dados);
}
}
buscarData();

Por fim, retorne o carregando, erro, e dados variáveis ​​de estado como um objeto.

retornar { carregando, erro, dados };

Renderizando a lista de postagens dependendo da categoria solicitada

Sempre que o usuário navega para / ou /:type, React deve renderizar o ListPage componente. Para implementar essa funcionalidade, primeiro importe os módulos necessários:

importar { useNavigate, useParams } de"react-router-dom";
importar useFetch de"../hooks/useFetch";

Em seguida, defina o componente funcional e atribua o parâmetro dinâmico, tipo para o tipo variável. Se o parâmetro dinâmico não estiver disponível, defina o tipo variável para notícias. Em seguida, ligue para o useFetch gancho.

exportarpadrãofunçãoListPage() {
deixar { tipo } = useParams();
const navegue = useNavigate();
se (!tipo) tipo = "notícias";
const { carregando, erro, dados } = useFetch (tipo, nulo);
}

Em seguida, retorne o código JSX apropriado, dependendo de qual dos carregando, erro, ou dados variáveis ​​é verdadeiro.

se (erro) {
retornar<div>Algo deu errado!div>
}

se (carregando) {
retornar<div>Carregandodiv>
}

se (dados) {
documento.title = type.toUpperCase();
retornar<div>

'tipo de lista'>{tipo}</div>
{data.map(item =>
"item">
"título do item"
onClick={() => navegar(`/item/${item.id}`)}>
{título do item}
</div>
{item.domain &&
"link do item"
onClick={() => abrir(`${item.url}`)}>
({item.domain})</span>}
</div>)}
</div>
</div>
}

Criando o componente PostPage

Primeiro, importe os módulos e componentes apropriados, depois defina o componente funcional padrão, atribua o eu ia parâmetro dinâmico para o eu ia variável e, chame o useFetch gancho. Certifique-se de desestruturar a resposta.

importar { Link, useParams } de"react-router-dom";
importar analisar de'html-react-parser';
importar momento de"momento";
importar Comentários de"../componentes/Comentários";
importar useFetch de"../hooks/useFetch";

exportarpadrãofunçãoPostPage() {
const { id } = useParams();
const { carregando, erro, dados } = useFetch(nulo, eu ia);
}

E assim como com o ListPage componente, renderize o JSX apropriado com base no estado das seguintes variáveis: carregando, erro, e dados.

se (erro) {
retornar<div>Algo deu errado!div>
}

se (carregando) {
retornar<div>Carregandodiv>
}

se (dados) {
documento.title=data.title;
retornar<div>

"pós-título">{data.title}</div>
"pós-metadados">
{data.url &&
className ="post-link">Visite o site</Link>}
"pós-autor">{dados.autor}</span>
"pós-tempo">
{momento (data.created_at).fromNow()}
</span>
</div>
{dados.texto &&
"pós-texto">
{analisar (dados.texto)}</div>}
"Postar comentários">
"comments-label">Comentários</div>

</div>
</div>
}

Importar o analisar módulo e o momento módulo. Definir o componente funcional padrão Comentários que leva no comentáriosDados array como um prop, percorre os arrays e renderiza um componente para cada elemento.

importar analisar de'html-react-parser';
importar momento de"momento";

exportarpadrãofunçãoComentários({comentáriosDados}) {
retornar<>
{commentsData.map(comentárioDados =><comentárioDados={comentário}chave={commentData.id}
/>)}
</>
}

A seguir, defina o componente funcional logo abaixo do Comentários componente. O O componente renderiza o comentário, os metadados e as respostas a cada comentário (se houver) renderizando-se recursivamente.

função({comentárioDados}) {
retornar<divnome da classe="Comente">
{
comentárioDados.texto &&
<>
'comentário-metadados'>
{comentárioData.autor}</span>

{momento (commentData.created_at).fromNow()}
</span>
</div>
'comentário-texto'
>
{parse (comentárioData.text)}</div>
</>
}
'comentários-respostas'
>
{(comentárioData.children) &&
comentárioData.children.map(criança =>
)}
</div>
</div>
}

No bloco de código acima, analisar é responsável por analisar o HTML armazenado em comentárioDados.texto, enquanto momento é responsável por analisar o tempo do comentário e retornar o tempo relativo usando o a partir de agora() método.

Criando o componente Navbar

Abra o Navbar.jsx arquivo e importar o NavLink módulo do react-router-dom módulo. Por fim, defina o componente funcional e retorne um pai navegação elemento com cinco NavLink elementos apontando para as categorias apropriadas (ou tipos).

importar { NavLink } de"react-router-dom"

exportarpadrãofunçãobarra de navegação() {
retornar<navegação>
"/notícias">Casa</NavLink>
"/melhor">Melhor</NavLink>
"/mostrar">Mostrar</NavLink>
"/perguntar">Pergunte</NavLink>
"/empregos">Empregos</NavLink>
</nav>
}

Parabéns! Você acabou de criar seu próprio cliente front-end para o Hacker News.

Solidifique suas habilidades de reação criando um aplicativo clone

Construir um clone do Hacker News com o React pode ajudar a solidificar suas habilidades no React e fornecer um aplicativo prático de página única para trabalhar. Há muitas maneiras de levar as coisas adiante. Por exemplo, você pode adicionar a capacidade de pesquisar postagens e usuários ao aplicativo.

Em vez de tentar construir seu próprio roteador do zero, é melhor usar uma ferramenta desenvolvida por profissionais que se dedicam a facilitar a criação de SPAs.