Я пытаюсь создать приложение, которое отображает источники новостей в виде списка, и у каждого источника есть ссылка «Лучшие заголовки», которая переводит URL в конечную точку «/ заголовки». На этой конечной точке я хочу отобразить список верхних заголовков из указанного источника новостей c.
Приложение. js
import React, { useState, useEffect } from "react";
import Sources from "./components/Sources";
import Pagination from "./components/Pagination";
import Headlines from "./components/Headlines";
import axios from "axios";
import { Key } from "./API_Key"; // Import API key from outside the code.
import "./App.css";
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
const App = () => {
// Initialize states
const [sources, setSources] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [sourcesPerPage] = useState(10);
useEffect(() => {
// Get news sources from News API
const fetchNews = async () => {
setLoading(true);
const res = await axios.get(
`http://newsapi.org/v2/sources?apiKey=${Key}`
);
setSources(res.data.sources); // Add news sources to "sources" state
setLoading(false);
console.log(res.data.sources.map(source => source.id));
};
fetchNews();
}, []);
const indexOfLastSource = currentPage * sourcesPerPage; // Get last source index
const indexOfFirstSource = indexOfLastSource - sourcesPerPage; // Get first source index
const currentSources = sources.slice(indexOfFirstSource, indexOfLastSource); // Get current sources
// Change page
const paginate = pageNumber => setCurrentPage(pageNumber);
return (
<Router>
<div className="container-fluid bg-dark mb-0">
<div className="container pt-3 pb-5">
<h3>
<Link to="/" className="badge badge-info">
Back to sources
</Link>
</h3>
<h1 className="text-primary mb-3">News from News API</h1>
<Switch>
<Route
exact
path="/"
render={props => (
<React.Fragment>
<Sources sources={currentSources} loading={loading} />
<Pagination
sourcesPerPage={sourcesPerPage}
totalSources={sources.length}
paginate={paginate}
/>
</React.Fragment>
)}
/>
<Route
path="/headlines"
render={props => (
<React.Fragment>
<Headlines sources={currentSources} loading={loading} />
<Pagination
sourcesPerPage={sourcesPerPage}
totalSources={sources.length}
paginate={paginate}
/>
</React.Fragment>
)}
/>
</Switch>
<h3 className="mb-0">
<a
href="https://newsapi.org/"
className="badge badge-info"
target="_blank"
rel="noopener noreferrer"
>
Powered by News API
</a>
</h3>
</div>
</div>
</Router>
);
};
export default App;
Источники новостей отправляется в качестве реквизита в Sources-component для отображения списка источников. А также компоненту Headlines для получения доступа к source.id
Sources. js
import React from "react";
import { Link } from "react-router-dom";
const Sources = ({ sources, loading }) => {
if (loading) {
return <h2>Loading...</h2>; // Show text "Loading..." if loading not done.
}
/* Map through the sources received as props, and return them as a list */
return (
<ul className="list-group mb-4">
{sources.map(source => (
<li key={source.id} className="list-group-item itemhover">
<h4>{source.name}</h4>
<p>{source.description}</p>
<Link to="/headlines" className="btn btn-success mr-5">
Top headlines
</Link>
<a href={source.url} target="_blank" rel="noopener noreferrer">
{source.url}
</a>
</li>
))}
</ul>
);
};
export default Sources;
Массив источников новостей отображается через и компонент возвращает элемент списка для каждого источника со ссылкой на верхние заголовки.
Заголовки. js
import React from "react";
const Headlines = ({ headlines, loading }) => {
if (loading) {
return <h2>Loading...</h2>; // Show text "Loading..." if loading not done.
}
/* Map through the headlines received as props, and return them as a list */
return (
<ul className="list-group mb-4">
{headlines.map(headline => (
<li key={headline.id} className="list-group-item itemhover">
<h4>{headline.title}</h4>
<p>{headline.description}</p>
<a href={headline.url} target="_blank" rel="noopener noreferrer">
{headline.url}
</a>
</li>
))}
</ul>
);
};
export default Headlines;
В компоненте Заголовки я хочу отобразить заголовки из второго вызова и вернуть список верхних заголовков из указанного источника c.
Например, если я нажму ссылку "Верхние заголовки" внутри BB C Элемент списка новостей, тогда конечная точка "/ заголовки" должна показывать только верхние заголовки с BB C.
Проблема в том, что я не знаю, где разместить второй вызов для заголовков. Я попытался поместить его в Headlines-компонент, а затем использовать source.id, который становится опорой в новом вызове (помещая его в строку шаблона в качестве переменной), но это привело к бесконечной волне запросов http, которые замерзли Некоторое время в моем браузере и после того, как мне удалось остановить выполнение кода, API новостей заблокировал меня из-за тайм-аута (ошибка 429 для слишком большого числа запросов).
Идея в двух словах:
- На первой странице показан список источников, каждый из элементов списка имеет ссылку на верхние заголовки.
- После нажатия на ссылку, URL перемещается в «/ заголовки», где страница отображает заголовки для указанного c источника.
Может кто-нибудь сказать мне, если я пропускаю только маленький кусочек головоломки или мне нужно сделать основную переписать в иерархия рендеринга?
Естественно, я не буду здесь давать свой ключ API, поэтому, к сожалению, вы не сможете проверить это, если у вас нет ключа от News API.
GitHub repo
* 10 46 * РЕДАКТИРОВАТЬ: Теперь, когда я думаю об этом, могу ли я отправить
source.id в качестве реквизита через компонент Link to Headlines?
Я видел что-то вроде этого:
<Link to={{ pathname: '/headlines', source: { sourceID: source.id } }}>Top headlines</Link>
Но как мне получить доступ к этому в компоненте Headline?
Так как я использую компоненты функций, this.props.location.source не будет работать.
Есть какой-то хук для этого или чего-то еще?
ОБНОВЛЕНИЕ: я добавил это в Headline-компонент:
const { source } = useParams();
Но теперь я получаю ошибку:
React Hook "useParams" вызывается условно. React Hooks должны вызываться в том же порядке в каждом компоненте рендера. Вы случайно позвонили в React Hook после раннего возвращения?