First time using React this week and I'm trying to create a fetch Github app, everything is working but the scroll to the top. When I scroll down and click on the view Repo I want the screen to automatically scroll up, I've copied the code via the React Docs and I am using React-Router-Dom version 5 however nothing is scrolling up. Please see below for my code, where am I going wrong guys?
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
App.js
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import './App.css';
import RepoPage from './components/RepoPage';
import ScrollToTop from './components/ScrollToTop';
function App() {
return (
<Router>
<div className="App">
<h1>Want to see other people's projects? Enter a Github username and Voila!</h1>
<ScrollToTop />
<Switch>
<Route>
<RepoPage />
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
Snippet of my Repo.js component
import React, {useEffect, useState} from 'react';
import axios from 'axios';
import RepoDetails from './RepoDetails';
import ScrollToTop from './ScrollToTop';
import '../App.css'
function renderRows(repo) {
return(
<div
className='repo-button'
onClick={() => getDetails(repo.name)}
key={repo.id}
>
<h3 className='repo-name'>
{repo.name}
<button onCLick={<ScrollToTop />}>View Repo</button>
</h3>
</div>
)
}
There might be some misunderstanding with how ScrollToTop function component is used. I think when used in the App component, it is meant to automatically scroll to the top when the pathname changes. We can probably add this similar behavior for when the View Repo button is clicked by passing a callback function to onClick like () => window.scrollTo(0, 0) instead of the function component.
Not to worry I've fixed the issue, I've set the window scroll to the top within the button onClick tag. Thanks anyway
Related
i'm trying to make multiple pages in react app , and I'm confused how to set my codes properly;I have a component folder which has Navbar.jsx which I have my nav items that i want to send me to another page when i click(react-route) . and I have the Container folder which has Header.jsx and that what i want to change based on the nav items clicked.
import React, { useState } from 'react';
import { RiMenu3Line, RiCloseLine } from 'react-icons/ri';
import './Navbar.css';
import logo from '../../assets/logo.png'
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams
} from "react-router-dom";
const Menu = () => (
<>
<Router>
<p><Link to={"/about"}>About</Link></p>
<p><Link to={"/contact"}>Contact</Link></p>
</Router>
</>
)
const Navbar = () => {
...
Header.jsx I didnt change any thing
const Header = () => {
return (...
I have routes.js -
import React from 'react'
import { Switch, Route , Link } from 'react-router';
import {BrowserRouter, Router} from 'react-router-dom';
import SignIn from './Components/Login/SignIn';
import MainPage from './Components/MainPage';
function Routes() {
return (
<Router>
<Switch>
<Route path="/logout" component={SignIn} ></Route>
<Route path="/home" component={MainPage} ></Route>
</Switch>
</Router>
)
}
export default Routes
Within SignIn.js I have button from which I want to render to main page.
Main bits of SignIn.Js are as below -
import MainPage from '../MainPage';
import { useHistory } from 'react-router-dom';
<FormGroup>
<Button style={{width:'100%',backgroundColor:"#FCB724",color:"black",fontWeight:"bold"}} onClick={NavigateToMainPage} >Sign in using our secure server</Button>
</FormGroup>
function NavigateToMainPage(){
let path = `/home`;
let history = useHistory();
history.push(path);
}
This is not navigating.
How can I navigate on button click to another component in this case ?
I'm not sure how this code isn't breaking completely because you can't use a hook outside of a react component, you can't use it in a normal function.
const Form = () => {
const history = useHistory()
return <form>
<button onClick={() => history.push('/home')}>Example</button>
</form>
}
You want something like that.
You have to change how you call a function inside an on click prop.
If you write onClick={functionName}, the functionName would be always executed when the component is rendered and it would produce an infinite loop.
You have to change it into this onClick={() => functionName()} means that the functionName will be executed only after the the onclick is executed.
Don't forget to add return to the component.
Also if you use hook (like something starts from use word), you have to put it inside the functional component.
Here is the full code:
import MainPage from '../MainPage';
import { useHistory } from 'react-router-dom';
const SignIn = () => {
const NavigateToMainPage = () => {
let path = `/home`;
let history = useHistory();
history.push(path);
}
return(
<FormGroup>
<Button
style={{width:'100%',backgroundColor:"#FCB724",color:"black",fontWeight:"bold"}}
onClick={() => NavigateToMainPage()}
>
Sign in using our secure server
</Button>
</FormGroup>
)
}
export default SignIn
Additional info:
I personally use const (ES6 arrow function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) rather than function to declare a function.
In the MainPage.js, you can directly import the Route, Switch, and Link from react-router-dom.
So you can change it from this:
import {Switch, Route , Link} from 'react-router';
import {BrowserRouter, Router} from 'react-router-dom';
into this:
import {BrowserRouter, Router, Switch, Route, Link} from 'react-router-dom';
I'd implement your example using NavLink component instead of useHistory hook.
import MainPage from '../MainPage';
import { NavLink} from 'react-router-dom';
<FormGroup>
<NavLink to="/home" style={{width:'100%',backgroundColor:"#FCB724",color:"black",fontWeight:"bold"}} onClick={NavigateToMainPage}>Sign in using our secure server</NavLink>
</FormGroup>
To top it off, please use const variables, forget about var.
I have a list of items, in a table in React. When I click on the table Link, the url updates, but the component doesn't get rendered. If I refresh the component is there.
I have read that some React-router-dom versions have some problems, and there are a lot of solutions that are being discussed here:
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
That although is for the Beta Versions. I assume I need to do something with the higher order function withRouter from react-router-dom, but it doesn't work for me. On top of that, withRouter has been set up globally in the App.
const AppHeader = withRouter(({ history, location, ...props }) => (
<Header {...props} currentRoute={location.pathname} />
));
The thing is, my App has several applications. One Angular and 2 React ones. Do I need to set it up, on each application as well? This is the Parent Component with the router for the application the Links aren't working.
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import 'react-tagsinput/react-tagsinput.css';
import PolicyRoutes from 'dataprotection/policies/containers/PolicyRoutes';
import './styles.scss';
const AppRouter = () => (
<Switch>
<Route exact path="/policies" component={PolicyRoutes} />
<Redirect to="/policies" />
</Switch>
);
AppRouter.propTypes = {};
function mapStateToProps() {
return {};
}
export default connect(mapStateToProps)(AppRouter);
I have tried 2 solutions. The first is to actually wrap my component withRouter like so:
<Route exact path="/policies" component={withRouter(PolicyRoutes)} />
And the second is to wrap withRouter, the connect function. Both aren't working.
This is the component not working:
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import PropTypes from 'prop-types';
import OverviewScreen from '../OverviewScreen';
import PolicyDetailsScreen from '../PolicyDetailsScreen';
const PolicyRoutes = ({ match }) => (
<Switch>
<Route exact path={`${match.url}/details/:policyId`} component={PolicyDetailsScreen} />
<Route exact path={match.url} component={OverviewScreen} />
<Redirect to={match.url} />
</Switch>
);
PolicyRoutes.propTypes = {
match: PropTypes.object
};
export default PolicyRoutes;
Can anyone help? I don't know what the problem is...
Trying to figure out how can I go back to the previous page. I am using [react-router-v4][1]
This is the code I have configured in my first landing page:
<Router>
<div>
<Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
<Route exact path="/" component={Page1}/>
<Route path="/Page2" component={Page2}/>
<Route path="/Page3" component={Page3}/>
</div>
</Router>
In order to forward to subsequent pages, I simply do:
this.props.history.push('/Page2');
However, how can I go back to previous page?
Tried few things like mentioned below but no luck:
1. this.props.history.goBack();
Gives error:
TypeError: null is not an object (evaluating 'this.props')
this.context.router.goBack();
Gives error:
TypeError: null is not an object (evaluating 'this.context')
this.props.history.push('/');
Gives error:
TypeError: null is not an object (evaluating 'this.props')
Posting the Page1 code here below:
import React, {Component} from 'react';
import {Button} from 'react-bootstrap';
class Page1 extends Component {
constructor(props) {
super(props);
this.handleNext = this.handleNext.bind(this);
}
handleNext() {
this.props.history.push('/page2');
}
handleBack() {
this.props.history.push('/');
}
/*
* Main render method of this class
*/
render() {
return (
<div>
{/* some component code */}
<div className="navigationButtonsLeft">
<Button onClick={this.handleBack} bsStyle="success">< Back</Button>
</div>
<div className="navigationButtonsRight">
<Button onClick={this.handleNext} bsStyle="success">Next ></Button>
</div>
</div>
);
}
export default Page1;
I think the issue is with binding:
constructor(props){
super(props);
this.goBack = this.goBack.bind(this); // i think you are missing this
}
goBack(){
this.props.history.goBack();
}
.....
<button onClick={this.goBack}>Go Back</button>
As I have assumed before you posted the code:
constructor(props) {
super(props);
this.handleNext = this.handleNext.bind(this);
this.handleBack = this.handleBack.bind(this); // you are missing this line
}
UPDATED:
Now we have hook, so we can do it easily by using useHistory
const history = useHistory()
const goBack = () => {
history.goBack()
}
return (
<button type="button" onClick={goBack}>
Go back
</button>
);
ORIGINAL POST:
this.props.history.goBack();
This is the correct solution for react-router v4
But one thing you should keep in mind is that you need to make sure this.props.history is existed.
That means you need to call this function this.props.history.goBack(); inside the component that is wrapped by < Route/>
If you call this function in a component that deeper in the component tree, it will not work.
EDIT:
If you want to have history object in the component that is deeper in the component tree (which is not wrapped by < Route>), you can do something like this:
...
import {withRouter} from 'react-router-dom';
class Demo extends Component {
...
// Inside this you can use this.props.history.goBack();
}
export default withRouter(Demo);
For use with React Router v4 and a functional component anywhere in the dom-tree.
import React from 'react';
import { withRouter } from 'react-router-dom';
const GoBack = ({ history }) => <img src="./images/back.png" onClick={() => history.goBack()} alt="Go back" />;
export default withRouter(GoBack);
Each answer here has parts of the total solution. Here's the complete solution that I used to get it to work inside of components deeper than where Route was used:
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
^ You need that second line to import function and to export component at bottom of page.
render() {
return (
...
<div onClick={() => this.props.history.goBack()}>GO BACK</div>
)
}
^ Required the arrow function vs simply onClick={this.props.history.goBack()}
export default withRouter(MyPage)
^ wrap your component's name with 'withRouter()'
Here is the cleanest and simplest way you can handle this problem, which also nullifies the probable pitfalls of the this keyword. Use functional components:
import { withRouter } from "react-router-dom";
wrap your component or better App.js with the withRouter() HOC this makes history to be available "app-wide". wrapping your component only makes history available for that specific component``` your choice.
So you have:
export default withRouter(App);
In a Redux environment export default withRouter( connect(mapStateToProps, { <!-- your action creators -->})(App), ); you should even be able to user history from your action creators this way.
in your component do the following:
import {useHistory} from "react-router-dom";
const history = useHistory(); // do this inside the component
goBack = () => history.goBack();
<btn btn-sm btn-primary onclick={goBack}>Go Back</btn>
export default DemoComponent;
Gottcha useHistory is only exported from the latest v5.1 react-router-dom so be sure to update the package. However, you should not have to worry.
about the many snags of the this keyword.
You can also make this a reusable component to use across your app.
function BackButton({ children }) {
let history = useHistory()
return (
<button type="button" onClick={() => history.goBack()}>
{children}
</button>
)
}```
Cheers.
Can you provide the code where you use this.props.history.push('/Page2');?
Have you tried the goBack() method?
this.props.history.goBack();
It's listed here https://reacttraining.com/react-router/web/api/history
With a live example here https://reacttraining.com/react-router/web/example/modal-gallery
If using react hooks just do:
import { useHistory } from "react-router-dom";
const history = useHistory();
history.go(-1);
UPDATE 2022 w V6
navigate(-1)
to omit the current page from history:
navigate(-1, { replace: true })
Try:
this.props.router.goBack()
Simply use
<span onClick={() => this.props.history.goBack()}>Back</span>
Hope this will help someone:
import React from 'react';
import * as History from 'history';
import { withRouter } from 'react-router-dom';
interface Props {
history: History;
}
#withRouter
export default class YourComponent extends React.PureComponent<Props> {
private onBackClick = (event: React.MouseEvent): void => {
const { history } = this.props;
history.goBack();
};
...
Maybe this can help someone.
I was using history.replace() to redirect, so when i tried to use history.goBack(), i was send to the previous page before the page i was working with.
So i changed the method history.replace() to history.push() so the history could be saved and i would be able to go back.
I am not sure if anyone else ran into this problem or may need to see this. But I spent about 3 hours trying to solve this issue:
I wanted to implement a simple goBack() on the click of a button. I thought I was off to a good start because my App.js was already wrapped in the Router and I was importing { BrowserRouter as Router } from 'react-router-dom'; ... Since the Router element allows me to assess the history object.
ex:
import React from 'react';
import './App.css';
import Splash from './components/Splash';
import Header from './components/Header.js';
import Footer from './components/Footer';
import Info from './components/Info';
import Timer from './components/Timer';
import Options from './components/Options';
import { BrowserRouter as Router, Route } from 'react-router-dom';
function App() {
return (
<Router>
<Header />
<Route path='/' component={Splash} exact />
<Route path='/home' component={Info} exact />
<Route path='/timer' component={Timer} exact />
<Route path='/options' component={Options} exact />
<Footer />
</Router>
);
}
export default App;
BUT the trouble was on my Nav (a child component) module,
I had to 'import { withRouter } from 'react-router-dom';'
and then force an export with:
export default withRouter(Nav);
ex:
import React from 'react';
import { withRouter } from 'react-router-dom';
class Nav extends React.Component {
render() {
return (
<div>
<label htmlFor='back'></label>
<button id='back' onClick={ () => this.props.history.goBack() }>Back</button>
<label htmlFor='logOut'></label>
<button id='logOut' ><a href='./'>Log-Out</a>
</button>
</div>
);
}
}
export default withRouter(Nav);
in summary, withRouter was created because of a known issue in React where in certain scenarios when inheritance from a router is refused, a forced export is necessary.
You can use history.goBack() in functional component. Just like this.
import { useHistory } from 'react-router';
const component = () => {
const history = useHistory();
return (
<button onClick={() => history.goBack()}>Previous</button>
)
}
I am try to make inventory list app with react and redux , but I have a small problem with need some understanding about it .
I know we have few way to create react components and try to get as much as possible all information , but still not sure why this issue is happen .
I have app.js which is my all React-Router set there
console.log('The application has been start...');
import React from 'react'
import { render } from 'react-dom'
import { IndexPage } from './modules/IndexPage'
import { AddItemForm } from './modules/ui/AddItemForm'
import { PageNotFound } from './modules/PageNotFound'
import { Router, Route, hashHistory } from 'react-router'
import routes from './routes'
window.React = React
render(
<Router history={hashHistory}>
<Route path='/' component={IndexPage}/>
<Route path='/add' component={AddItemForm}/>
<Route path='*' component={PageNotFound}/>
</Router>,
document.getElementById('react-container')
)
for IndexPage and PageNotFound the router display and render correctly , But for add , is display blank page with no error .
import { PropTypes } from 'react'
const AddItemForm = ({ onNewItem=f=>f, router}) => {
//const AddItemForm = () => {
let _itemName
const submit = e => {
e.preventDefault()
onNewItem({
itemName: _itemName.value,
itemCount: 1
})
router.push('/')
_itemName.value = ''
}
return (
<form onSubmit={submit} >something
<label htmlFor="item-name"> Name Item</label>
<input id="item-name" type="text" ref={(input) => _itemName = input } />
<button>Add Item</button>
</form>
)
}
AddItemForm.propTypes = {
onNewItem: PropTypes.func,
router: PropTypes.object
}
export default AddItemForm
in order to make sure there is something wrong with React-Router or the components which I made I change the AddItemForm with below code
export const AddItemForm = () =>
<div>
<h1>Oops ! - The page is working!</h1>
</div>
which start working normally which shows something wrong with my components but I am not able to understand what is the main issue. Please give me hit or point where is the issue or what is the different ?
Here is link of github for full source of application so far
https://github.com/msc/Inventory-List
I tried to reproduce this issue. What I figured out is that you also need to import React for your component along with PropTypes.
So try importing React
import React, { PropTypes } from 'react'
in your AddItemForm component. Then worked for me.