I have this case where, in the nav bar I have different categories eg Science, business etc. When clicked on ay of these we are supposed to render News component with the appropriate category.
But in my case on clicking on any of the link, although the address bar did change but news component was not being reloaded with the new category that I provided.
Here are my files :
App.js
import './App.css';
import React, { Component } from 'react'
import NavBar from './components/NavBar';
import News from './components/News';
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
export default class App extends Component {
constructor() {
super();
this.category = 'about';
this.uniqueKeyForRemountingNewsComponent = '';
}
render() {
return (
<Router>
<div>
<NavBar/>
<Switch>
<Route exact path="/about">
</Route>
<Route exact path="/business">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'business'}
</Route>
<Route exact path="/entertainment">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'entertainment'}
</Route>
<Route exact path="/general">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'general'}
</Route>
<Route exact exactpath="/health">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'health'}
</Route>
<Route exact path="/science">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'science'}
</Route>
<Route exact path="/sports">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'sports'}
</Route>
<Route exact path="/technology">
{this.uniqueKeyForRemountingNewsComponent = this.category = 'technology'}
</Route>
</Switch>
<News key={this.uniqueKeyForRemountingNewsComponent} pageSize={5} country="in" category={this.category}/>
</div>
</Router>
)
}
}
NavBar.js
import React, { Component } from 'react'
import {
Link
} from "react-router-dom";
export class NavBar extends Component {
render() {
return (
<div>
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<div className="container-fluid">
<Link className="navbar-brand" to="/">NewsMonkey</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav me-auto mb-2 mb-lg-0">
<li className="nav-item">
<Link className="nav-link active" aria-current="page" to="/">Home</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/business">Business</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/entertainment">Entertainment</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/general">General</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/health">Health</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/science">Science</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/sports">Sports</Link>
</li>
<li className="nav-item">
<Link className="nav-link" to="/technology">Technology</Link>
</li>
</ul>
</div>
</div>
</nav>
</div>
)
}
}
export default NavBar
News.js
import React, { Component } from 'react'
import NewsItem from './NewsItem'
import Spinner from './Spinner'
import PropTypes from 'prop-types'
export class News extends Component {
static defaultProps = {
country: 'in',
pageSize: 5,
category: 'general'
}
static propTypes = {
country: PropTypes.string.isRequired,
pageSize: PropTypes.number.isRequired,
category: PropTypes.string.isRequired,
}
constructor(){
super();
this.state = {
articles:[],
loading:true,
page:1,
totalResults : 0
}
}
async componentDidMount() {
let url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=APIKEY&page=1&pageSize=${this.props.pageSize}`;
this.setState({loading: true});
let data = await fetch(url);
console.log(data);
let parsedData = await data.json();
this.setState({articles: parsedData.articles, totalResults: parsedData.totalResults, loading: false})
console.log(this.state);
}
handlePrevClick = async ()=>{
let currentPage = this.state.page;
let url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=APIKEY&page=${currentPage-1}&pageSize=${this.props.pageSize}`;
this.setState({loading: true});
let data = await fetch(url);
console.log(data);
let parsedData = await data.json();
console.log(parsedData);
if(parsedData)
this.setState({articles: parsedData.articles, page : currentPage - 1, loading: false});
console.log(this.state);
}
handleNextClick = async ()=>{
let currentPage = this.state.page;
let url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=APIKEY&page=${currentPage+1}&pageSize=${this.props.pageSize}`;
this.setState({loading: true});
let data = await fetch(url);
console.log(data);
let parsedData = await data.json();
console.log(parsedData);
if(parsedData)
this.setState({articles: parsedData.articles, page : currentPage + 1, loading: false});
console.log(this.state);
}
render() {
return (
<div className="container my-3">
<h3 className="text-center">NewsMonkey - Top headlines</h3>
{this.state.loading && <Spinner/>}
<div className="row">
{!this.state.loading && this.state.articles.map((element)=>{
return (
<div className="col-md-4" key={element.url}>
<NewsItem title={element && element.title?element.title.slice(0, 45): ""} description={element && element.description?element.description.slice(0, 50):""}
imageUrl={element.urlToImage}
newsUrl ={element.url}/>
</div>
)})}
</div>
<div className="container d-flex justify-content-between">
<button type="button" disabled={this.state.page<=1} className="btn btn-dark" onClick={this.handlePrevClick} >← Prev</button>
<button type="button" disabled={this.props.pageSize*this.state.page>=this.state.totalResults} className="btn btn-dark" onClick={this.handleNextClick}>Next →</button>
</div>
</div>
)
}
}
export default News
you shouldn't try to set a variable but just directly put the component
every time you hit a /business it will render the component that is a child of
<Route exact path="/business">
if you call /entertainment, it renders the child component you put under
<Route exact path="/entertainment">
and so on
If you want to make that a bit more "clean", you could create a component that returns a Route
I haven't tested this code but you get the idea