Reputation: 33
I'm trying to build a React app which fetches news from the news API and displays it based on the category. It uses Infinite scrolling and displays 6 news items at a time.
export default class App extends Component {
render() {
return (<>
<BrowserRouter>
<Navbar />
<Routes>
<Route exact path="/general" key="general" element={<News category={'general'} />} />
<Route exact path="/sports" key="sports" element={<News category={'sports'} />} />
<Route exact path="/entertainment" key="entertainment" element={<News category={'entertainment'} />} />
<Route exact path="/health" key="health" element={<News category={'health'} />} />
<Route exact path="/science" key="science" element={<News category={'science'} />} />
<Route exact path="/" key="everything" element={<News/>} />
</Routes>
</BrowserRouter>
</>
)
}
}
here is the code of News component
export default class News extends Component {
static defaultProps = {
pageLimit: 6,
category:'',
country: 'in'
}
static propTypes = {
pageLimit: PropTypes.number.isRequired,
country: PropTypes.string.isRequired
}
constructor() {
super();
this.state = {
articles: [],
loading: true,
page: 1,
totalResults: 1,
pageSize: 1
}
}
async componentDidMount() {
let url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&apiKey=445f58e1d17c4229b23e3965d19197c7&category=${this.props.category}&page=1&pagesize=${this.props.pageLimit}`;
let res = await fetch(url);
let data = await res.json();
this.setState({
loading: false,
totalResults: data.totalResults,
articles: data.articles,
pageSize: Math.ceil(data.totalResults / this.props.pageLimit)
});
}
fetchData = async () => {
let url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&apiKey=445f58e1d17c4229b23e3965d19197c7&category=${this.props.category}&page=${this.state.page + 1}&pagesize=${this.props.pageLimit}`;
this.setState({
loading: true,
page: this.state.page + 1,
})
let res = await fetch(url);
let data = await res.json();
this.setState({
loading: false,
articles: this.state.articles.concat(data.articles),
});
}
render() {
return (<>
<InfiniteScroll
dataLength={this.state.articles.length}
next={this.fetchData}
hasMore={this.state.articles.length !== this.state.totalResults}
loader={<Spinner />}
>
<div className='container'>
<div className='row'>
{
this.state.articles.map((elem) => {
return <div className='col-md-4' key={elem.url}>
<Newscomp title={elem.title ? elem.title.slice(0, 30) : ""} url={elem.url} imgUrl={elem.urlToImage} description={elem.content ? elem.content.slice(0, 40) : ""} />
</div>
})
}
</div>
</div>
</InfiniteScroll>
</>
)
}
}
when I try to change the category lets say from general to sports the previous 6 news items from general remain but on scrolling down I get the news from sports category.
I want it to completely remove the previous content and show the newly fetched content when I switch categories. How can I do that?
Upvotes: 3
Views: 3853
Reputation: 202608
This is an optimization when 2 or more routes render the same routed component. In this case, the News
component. The News
component will remain mounted and only the category
prop is changing, so the News
component can respond to that change. You have a couple options:
Move the key
to the correct component. It is rather irrelevant on the Route
component. Move the key
prop to the routed component to "force remount" it.
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/general" element={<News key="general" category={'general'} />} />
<Route path="/sports" element={<News key="sports" category={'sports'} />} />
<Route
path="/entertainment"
element={<News key="entertainment" category={'entertainment'} />}
/>
<Route path="/health" element={<News key="health" category={'health'} />} />
<Route path="/science" element={<News key="science" category={'science'} />} />
<Route path="/" element={<News key="everything" />} />
</Routes>
</BrowserRouter>
Implement the componentDidUpdate
lifecycle method to handle responding to the category
prop updating.
export default class News extends Component {
...
fetchInitialData = async () => {
const { category, country, pageLimit } = this.props;
this.setState({ loading: true }); // set loading state
const url = `https://newsapi.org/v2/top-headlines?country=${country}&apiKey=445f58e1d17c4229b23e3965d19197c7&category=${category}&page=1&pagesize=${pageLimit}`;
try {
const res = await fetch(url);
const data = await res.json();
this.setState({
totalResults: data.totalResults,
articles: data.articles,
pageSize: Math.ceil(data.totalResults / pageLimit)
});
} catch(error) {
// handle any rejected Promises or thrown errors
} finally {
this.setState({ loading: false }); // clear loading state
}
}
componentDidMount() {
fetchInitialData();
}
componentDidUpdate(prevProps) {
if (prevProps.category !== this.props.category) {
fetchInitialData();
}
}
...
}
Upvotes: 3