React Link doesn't refresh page automatically - reactjs

I am currently experiencing an issue similar to React Link doesn't refresh the page, however, the answer doesn't work well for my case.
See, I am currently using react-router to have a path called 'study/:id'. This :id variable will just be printed on the page
Here is the code for my BrowserRouter (App.js)
import React from 'react';
import './App.css';
import HomePage from './HomePage/HomePage';
import Study from './StudyPage/Study';
import {BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path="/" exact={true} component={HomePage}/>
<Route path="/Study/:id" exact={true} component={Study} />
</Switch>
</Router>
);
}
export default App;
Inside the Study component itself, it basically just has a menubar and an indicator on which courseId are we in:
import React from 'react';
import './Study.css';
import Menubar from '../Menubar';
import Sidebar from './Sidebar';
import Chapter from './Chapter';
class Study extends React.Component{
constructor(props){
super(props);
this.state = {
courseId: this.props.match.params.id,
};
}
render(){
return(
<div id="studyWrapper">
<Menubar />
<h1>We are on course: {this.state.courseId}</h1>
</div>
)
}
}
export default Study;
In order for the user to navigate through the study pages, I use a menubar component like this (Menubar.js)
import React from 'react';
import './Menubar.css';
import { Nav } from 'reactstrap';
import { Dropdown, DropdownButton } from 'react-bootstrap';
import { Link } from 'react-router-dom';
class Menubar extends React.Component{
constructor(props){
super();
this.state = {
courses: [],
reload: false
}
}
async componentDidMount(){
const response = await fetch("/v1/courses/")
const body = await response.json();
this.setState({
courses: body
});
}
render(){
const {courses} = this.state
return (
<Nav className="navbar navbar-expand-md navbar-light menubarStyle fixed-top">
<div className="container-fluid">
<a className="navbar-brand logo" href="/">LOGO</a>
<div className="navbar-collapse">
<div className="navbar-nav">
<div className="dropdown nav-item">
<DropdownButton variant='Secondary' id="dropdown-basic-button" title="Browse Courses">
<Dropdown.Item as={Link} to={`/study/001`} >001</Dropdown.Item>
<Dropdown.Item as={Link} to={`/study/002`} >002</Dropdown.Item>
<Dropdown.Item as={Link} to={`/study/003`} >003</Dropdown.Item>
</DropdownButton>
</div>
</div>
</div>
</div>
</Nav>
)
}
}
export default Menubar
IRL, the study page basically looks like this
The problem
The problem that I am having is that, once I am in '/study/001' page already (just like the picture above). If I try to click on DropdownItem 002 from the menuBar, the URL will change to 'study/002', but the page won't change. It will not refresh.
The solution from React Link doesn't refresh the page basically says to use windows.location.reload() but that doesn't work in my case, if we do that, when I click on dropdownItem 002, the URL will change to 'study/002' for a moment, but then 'study/001' will refresh thus making the page back to 001
My question is, is there a way for us to refresh the page whenever the url is changed by link ?
Or if not, are there any other methods that I can use for this design? Maybe using links is not the right way in the first place?
Pardon the long post, I try to make it as clear as possible.
Thank you !

Inside your Study component you could use componentDidUpdate and compare the current props with the prevProps to check if the url has changed and then change the state, which should cause your component to update. More or less you would have this code:
componentDidUpdate(prevProps) {
if( this.props.match.params.id !== prevProps.match.params.id ){
this.setState({ courseId: this.props.match.params.id })
};
}

Related

React redux state is not loading on production build

So i m having a very wired issue with react app its working fine in localhost but not working on production server.
In detail
im using react with redux and redux state is coming empty on production server
Image 1: Localhost Screen shot (which is working fine)
Image 2: Production Server Image Where menu state is empty (Not Working)
**
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom'
//global settings
import {SETTINGS} from '../../global/settings';
//calling component
import MenuItem from './menu-items.component';
//menu acctions
import {SET_MENU,SET_LOADING_STATUS} from '../../redux/menu/menu.actions';
//global JSON
import {JSON_URLS} from '../../global/json-urls';
//Nav bar
import {Collapse, Navbar,NavbarToggler,NavbarBrand,Nav,NavbarText,NavItem,} from 'reactstrap';
//reactstrap Spinner for loading
import { Spinner } from 'reactstrap';
class Menu extends React.Component{
constructor(){
super();
this.state={
isOpen: false,
setIsOpen: false,
}
}
componentDidMount(){
const {SET_MENU} = this.props;
const {SET_LOADING_STATUS}= this.props;
fetch('https://wp2.neton.com.au/wp-json/wp-api-menus/v2/menus/2')
.then(response =>response.json())
.then(menu=>SET_MENU(menu))
.then(menu=>SET_LOADING_STATUS(false))
}
render(){
const {menu}=this.props;
const {loading}=this.props;
const {isOpen, setIsOpen}= this.state;
console.log('Menu '+menu);
//for Menu
const toggle = () => setIsOpen(!isOpen);
return(
<div className="menu-menu">
{
(Array.isArray(menu.items))
?
<Navbar color="light" light expand="md">
<NavbarBrand href="/">{SETTINGS.SITE_NAME}</NavbarBrand>
<NavbarToggler onClick={toggle} />
<Collapse isOpen={isOpen} navbar>
<Nav className="mr-auto" navbar>
{(menu.items).map(menu=><MenuItem key={menu.id} menu={menu} />)}
<NavItem><Link to={`${SETTINGS.BASE_URL}posts`} className="nav-link">All Posts</Link></NavItem>
<NavItem><Link to={`${SETTINGS.BASE_URL}pages`} className="nav-link">All Pages</Link></NavItem>
</Nav>
<NavbarText>Simple Text</NavbarText>
</Collapse>
</Navbar>
:
(loading)
?
<Spinner color="dark" className="text-center d-block m-auto" />
:
''
}
</div>
)
}
}
const mapStateToProps=(state)=>({
menu:state.menu.menu,
loading:state.menu.loading
})
const mapDispatchToProps=(dispatch)=>({
SET_MENU:menu=>dispatch(SET_MENU(menu)),
SET_LOADING_STATUS:status=>dispatch(SET_LOADING_STATUS(status))
})
export default connect(mapStateToProps,mapDispatchToProps)(Menu);
**
OK FINALLY FOUND THE BUG!!
so it has nothing to do with redux but the issue is related to react-router-dom
so when we will build production we have to make sure two things
package.json should include
"homepage": "https://YOUR-DOMIAN/DIRECTORY",
DIRECTORY:where the build files will go
in ROUTER THIS DIRECTORY SHOULD ALSO BE MENTION
<Switch>
<Route exact path="/DIRECTORY/" component={HomePage} />
<Switch>
I was having issue with 2 point hope it helps others :)

How to pass state to components rendered by Router

I am making a React portfolio and one of the components will be an image gallery (needless to say I am a newbie to React, I wonder, or I'd not be asking this question). To do so, I will use a package (react-image-gallery), which allows me to customize several items. I already installed, and it works well, but I need to customize it - hide thumbnails and "play" and "fullscreen" buttons.
According to the documentation, it is possible to do so via the state. The issue is that I am failing to do so because the navigation of the App uses a router, and although I tried hard, I could not make the state pass into the component placed on Router. This is the code of the main component (the equivalent to App) which is not working:
import "./styles.css";
import {
HashRouter,
NavLink,
Route
} from "react-router-dom";
import React, { Component } from "react";
import Development from "./Development";
import Home from "./Home";
import Intro from "./Intro";
import Media from "./Media";
import StudyCase from './StudyCase';
import Stuff from "./Stuff";
class Main extends Component {
constructor() {
super();
this.state = {
showThumbnails: false
};
}
render() {
return (
<HashRouter>
<div>
<ul className='top-menu'>
<li>
<NavLink className='navs hvr-pulse' to='/'>
Home
</NavLink>
</li>
<li>
<NavLink className='navs hvr-pulse' to='/dev'>
Development
</NavLink>
</li>
<li>
<NavLink className='navs hvr-pulse' to='/media'>
Media
</NavLink>
</li>
<li>
<NavLink className='navs' to='/study-case'>
Study Case
</NavLink>
</li>
</ul>
<span className='bottom-slider'></span>
<div className='content'>
<Route exact path='/' component={Intro} />
<Route path='/dev' component={Development} />
<Route path='/media' component={Media} />
<Route path='/study-case' render={props => (<StudyCase {...this.state} showThumbnails={this.state.showThumbnails}/>)}/>
</div>
</div>
</HashRouter>
);
}
}
export default Main;
Can some of the colleagues point the error I am doing to me? Thanks in advance for the availability.
After some hours looking for the solution, I nailed it, and it was pretty basic, so a newbie could find the answer. It happened that the <StudyCase/> component had a component itself, and the state should live there. I was led to error by the rationale of a gallery package I was working with before, where state had to be manipulated in the same page of the router. Here is the code of the <StudyCase/> component, with the working state, if someone may need at some point:
import ImageGallery from 'react-image-gallery';
import React from 'react';
class StudyCase extends React.Component {
constructor() {
super();
this.state = {
showThumbnails: false,
showPlayButton: false,
showFullscreenButton: false,
showGalleryFullscreenButton: false,
};
}
render() {
return (
<ImageGallery
items={images}
showThumbnails={this.state.showThumbnails}
showPlayButton={this.state.showPlayButton && this.state.showGalleryPlayButton}
showFullscreenButton={
this.state.showFullscreenButton && this.state.showGalleryFullscreenButton
}
/>
// <ImageGallery
// items={images}
// showThumbnails={this.state.showThumbnails} />;
);
}
}
const images = [
{
original: 'https://picsum.photos/id/1018/1000/600/',
thumbnail: 'https://picsum.photos/id/1018/250/150/',
},
{
original: 'https://picsum.photos/id/1015/1000/600/',
thumbnail: 'https://picsum.photos/id/1015/250/150/',
},
{
original: 'https://picsum.photos/id/1019/1000/600/',
thumbnail: 'https://picsum.photos/id/1019/250/150/',
},
];
export default StudyCase;

React-router custom prop not passing to component. ternary operator not working correctly

In React i have my App.js page where i keep my states. I'm importing user1.js component to App.js, and in user1.js component i have a link button that takes me to path /user2.
When i click the button, React will set state property called testValue to true and in user2.js page ternary operator should choose the first value - test works because of that. But for some reason it does not work.
Any help?
APP.JS
import React, { Component } from 'react';
import './App.css';
import User1 from './components/user1';
class App extends Component {
constructor(props){
super(props);
this.state = {
testValue:false
};
}
change = () => {
this.setState({
testValue:true
},() => {
console.log(this.state.testValue)
});
}
render() {
return (
<div className="App">
<User1 change={this.change}/>
</div>
);
}
}
export default App;
USER1.JS
import React from 'react';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import User2 from './user2.js';
const User1 = (props) => {
return(
<BrowserRouter>
<div>
<Link to ="/user2">
<button onClick={props.change}>Next page</button>
</Link>
<Switch>
<Route path="/user2" exact component={User2}/>
</Switch>
</div>
</BrowserRouter>
); // end of return
};
export default User1;
USER2.JS
import React from 'react';
const User2 = (props) => {
console.log(props)
return(
<div>
{props.testValue ?
<p>test works</p>
:
<p>test does not work</p>
}
</div>
);
};
export default User2;
This is what i expected - test works
This is what i got - test does not work
You want to pass a custom property through to a component rendered via a route. Recommended way to do that is to use the render method.
<Route path="/user2" exact render={(props) => <User2 {...props} testValue={true} />} />
I think a valid inquiry here would be what are you wanting to pass through as an extra prop? whats the use case here? You may be trying to pass data in a way you shouldn't (context would be nice :D).

Click on card then navigate to card page details in react

I created a page and show some card also some little details of cards
Now I want to click on any card navigate to this on show all details
How can I get to this page on react js ?
Is this need to Redux ?
I couldn't understand what you said completely, but you can use React-Router to navigate to different pages in Reactjs. To install it using npm, go to your Application directory and enter in command line npm install --save React-Router
Here is a simple code to navigate to different pages:
import React from "react";
import "./App.css";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const Home=()=>
(<div>
<h2>Home</h2>
</div>
);
const About=()=>
(<div>
<h2>About</h2>
</div>
);
class App extends React.Component {
render() {
return (
<Router>
<div>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<Route exact path="/" component={Home}/>
<Route exact path="/about" component={About}/>
</div>
</Router>
);
}
}
export default App;
I hope it helped...
No need of Redux for your issue.
You just use React-router. you just create two component 1. Cards.js, 2. CardDetails.js and navigate to card details on click event of cards in Card.js
Cards.js
import React from "react";
import { withRouter } from "react-router";
class Cards extends React.Component {
goToCarddetails = (cardId) => {
localStorage.setItem("selectedCard", cardId);
this.props.history.push('/card-details');
// you can manage here to pass the clicked card id to the card details page if needed
}
render() {
return ( <div>
<div onClick = {()=>this.goToCarddetails('cardId1')}> card 1 </div>
<div onClick = {()=>this.goToCarddetails('cardId2')}> card 2 </div>
<div onClick = {()=>this.goToCarddetails('cardId3')}> card 3 </div>
</div>
)
}
}
export default withRouter(Cards);
With above on clicking any card you will be navigated to card details page.
CardDetails.js
import React from "react";
class CardDetails extends React.Component {
render() {
let selectedCardId = localStorage.getItem("selectedCard");
// you can get this cardId anywhere in the component as per your requirement
return ( <div>
card details here
</div>
)
}
}
export default CardDetails;
Note : I'm using react-router 4 here in example.

Props don't seem to be passed along in a React app

I recently started working with React so forgive me if my question is very basic. Props in a component don't seem to be passed along.
Below is my code.
dogDetails component
import React from 'react';
const DogDetails = (props) => {
return (
<div>
<h4>{'Dog details of '+ props.breed}</h4>
</div>
)
};
export default DogDetails;
In Dog component I have a method that returns a DogDetails component as shown below.
import React , {Component} from 'react'
import Dog from './Dog/Dog';
import classes from './Dogs.css';
import Aux from '../../hoc/Auxillary/Auxillary';
import {Route} from 'react-router-dom';
import DogDetails from './Dog/DogDetails/DogDetails';
class Dogs extends Component {
state = {
loadedDogs: []
};
componentDidMount () {
this.setState({
loadedDogs:[]
})
}
dogDetailsHandler = (dog) =>{
console.log(dog.breed);
return <DogDetails breed={dog.breed}/>;
};
render() {
const loadDogs = this.state.loadedDogs.map(dog => {
return <Dog
url={dog.images[0].image1}
alt={dog.id}
breed={dog.breed}
temperament={dog.temperament}
id={dog.id}
key={dog.id}
clicked ={() => this.dogDetailsHandler(dog)}>
</Dog>
});
return (
<Aux>
{loadDogs}
</Aux>
)
}
}
export default Dogs;
I have omitted the content of the loadedDogs array to reduce the code size.
Below is the Dog component
import React from 'react';
import classes from './Dog.css';
import {Link, Route} from 'react-router-dom';
const dog = (props) => {
return(
<div className={classes.Dog}>
<div>
<img src={props.url} alt ={props.id}/>
</div>
<div>
<h4>{'Breed: ' + props.breed}</h4>
<h5>{'Temperament: ' + props.temperament}</h5>
<p>
<Link to = '#'>... Read more ...</Link>
</p>
<Link to={'/shop/'+ props.id}>
<button onClick={props.clicked}>Order</button>
</Link>
</div>
</div>
)
};
export default dog;
I'm routing the DogDetails in the MainContent component like this.
import React from 'react';
import classes from './MainContent.css';
import Dogs from './Dogs/Dogs';
import Contact from '../Contact/Contact';
import {Route} from 'react-router-dom';
import DogDetails from './Dogs/Dog/DogDetails/DogDetails';
const main = () =>{
return (
<div className={classes.MainContent}>
<Route path='/' exact component = {Dogs}/>
<Route path='/shop' exact component = {Dogs}/>
<Route path={'/shop/:id'} exact component={DogDetails}/>
<Route path='/contact' exact component ={Contact}/>
</div>
)
};
export default main;
Here is a sample code sandbox to demonstrate what I'm trying to work on. I want the DogDetails component to show up when the Order button is clicked.
Code Sandbox
The dogDetails component <h4> tag is returning undefined. Please help me find where I'm doing it wrong.
Capitalize both dogDetails and dogDetailsHandler
User-Defined Components Must Be Capitalized
from react docs
Codesandbox example
Since you are using routing, I'm not sure why you have a button handler inside of a routed <Link />. Clicking on this element will route you to /shop/:id, and the return method of dogDetailsHandler will do nothing.
I have emulated your code and added a <Route /> I'm not sure if this is what you are after, but when I click "Order", I'll get routed to /shop/:id with the DogDetails component being rendered as it should.
Add this routing component after your <Link /> component and see if this is the behavior you are after.
<Route path="/shop/:id" render={
() => <DogDetails {...props} />
} />

Resources