I am very new to React Js. I want to move from the App Page to the Contact page using react. I tried using the latest useNavigate feature of React . But as soon as I use that hook all the content on my page disappears. I have used the format mentioned in the documentation .
Here is my Code:-
App.Js
import React from "react";
import { useNavigate } from "react-router-dom";
const App = () => {
const navigate = useNavigate();
const goToContact = () => {
navigate('/Contact');
};
return (
<div>
<h1>Hello</h1>
<button onClick={()=>goToContact()}>Contact</button>
</div>
);
};
export default App;
Contact.js
const Contact = () => {
return (
<div>
<h1>Contact</h1>
</div>
);
}
export default Contact;
The file structure
The Output
Don't create the onClick handler as a callback and mention the route in a browser router element so the click gets where to go. To simply navigate would not do that
e.g:
<button onClick={goToContact}>Contact</button>
And for router use this:
<Routes location={location} key={location.pathname}>
<Route path="/Contact" element={<Contact/>} />
</Routes>
Routes and Route are available in react-router-dom v6.
Router needs to be accessed in App.js.
The router will not make any connection between the Contact component and the route '/Contact' on its own. You need to set up your routes to tell the router what it should render for each path. You can do this in App.js for example:
import React from "react";
import { useNavigate } from "react-router-dom";
import Contact from './Contact'
const App = () => {
const navigate = useNavigate();
const goToContact = () => {
navigate('/Contact');
};
return (
<Routes>
<Route path="/" element={(
<div>
<h1>Hello</h1>
<button onClick={()=>goToContact()}>Contact</button>
</div>
)} />
<Route path="/Contact" element={<Contact/>} />
</Routes>
);
};
export default App;
Note that I have moved the content into the "/" path, otherwise you would have that render next to the Contact page. You can set up any content that is repeated on each page (such as navigation) around the <Routes> element.
Iam trying to create a dynamic route in react js. what i want is whenever user passes a value in my route it should check from the api if that value exists it should display a particular page.
Iam sending a post request and getting back some data but iam unable to link it with my route. below is my code. also i want to know how can i verify the value user entered exists in my api.
my component
import React from "react";
import { useState, useEffect } from "react";
import { SignUpModal } from "../User/Signup/index";
import axios from "axios";
import { getToken } from "../../common/constants/variables";
function Reference() {
const [ref, setRef] = useState([]);
axios
.post(
"https://theappsouk.com/api/v1/check-referral",
{
ref: ref,
}
)
.then((response) => setRef(response.data));
console.log(JSON.stringify(ref))
return (
<div>
<h1>Hello </h1>
</div>
);
}
export default Reference;
my route
<Switch>
<Route path="/home" component{Home}/>
<Route path="/about" component{About}/>
<Route path="/contact" component{Contact}/>
<Route path="/ref" component{Reference}/> here i want to pass my ref object from above
</Switch>
here in ref i want to pass my data that is my ref which is to be checked against api.
<Route path="/:ref" component{Reference} />
const { useParams } from "react-router-dom";
function Reference() {
let { ref } = useParams();
...
}
I am using React Hooks and my state (moduleName) is not getting updated even though the prop(which i get from route)changes? I need to use moduleName to useEffect Dependencies to make Api Call.
I am also using withRouter at my component but it doesnt seem to rerender my component when route changes. My App.js looks like this
<Router>
<Fragment>
<Switch>
<Route path="/" exact={true} component={Login} />
<Route component={Routes} />
</Switch>
</Fragment>
</Router>
and at the component i need to re render on route changei have this
const ListView = (props) =>{
const [moduleName, setModuleName] =useState(props.match.params.moduleName);
useEffect(() => {
//api call here
}, [moduleName]);
}
export default connect(
mapStateToProps,
null
)(withRouter(ListView));**
You should listen prop changes inside the useEffect Hook, and you don't need to hold state for a prop, so you can delete useState hook
const ListView = (props) =>{
useEffect(() => {
let moduleName = props.match.params.moduleName
if(moduleName) {
console.log(props.match.params.moduleName)
// do something when moduleName changes
// api call
axios.get('someurl/'+moduleName)
}
}, [props.match.params.moduleName]);
}
export default withRouter(connect(mapStateToProps,null)(ListView));
I am developing an application in which I check if the user is not loggedIn. I have to display the login form, else dispatch an action that would change the route and load other component. Here is my code:
render() {
if (isLoggedIn) {
// dispatch an action to change the route
}
// return login component
<Login />
}
How can I achieve this as I cannot change states inside the render function.
Considering you are using react-router v4
Use your component with withRouter and use history.push from props to change the route. You need to make use of withRouter only when your component is not receiving the Router props, this may happen in cases when your component is a nested child of a component rendered by the Router and you haven't passed the Router props to it or when the component is not linked to the Router at all and is rendered as a separate component from the Routes.
import {withRouter} from 'react-router';
class App extends React.Component {
...
componenDidMount() {
// get isLoggedIn from localStorage or API call
if (isLoggedIn) {
// dispatch an action to change the route
this.props.history.push('/home');
}
}
render() {
// return login component
return <Login />
}
}
export default withRouter(App);
Important Note
If you are using withRouter to prevent updates from being blocked by
shouldComponentUpdate, it is important that withRouter wraps the
component that implements shouldComponentUpdate. For example, when
using Redux:
// This gets around shouldComponentUpdate
withRouter(connect(...)(MyComponent))
// This does not
connect(...)(withRouter(MyComponent))
or you could use Redirect
import {withRouter} from 'react-router';
class App extends React.Component {
...
render() {
if(isLoggedIn) {
return <Redirect to="/home"/>
}
// return login component
return <Login />
}
}
With react-router v2 or react-router v3, you can make use of context to dynamically change the route like
class App extends React.Component {
...
render() {
if (isLoggedIn) {
// dispatch an action to change the route
this.context.router.push('/home');
}
// return login component
return <Login />
}
}
App.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default App;
or use
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
In react-router version 4:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
const Example = () => (
if (isLoggedIn) {
<OtherComponent />
} else {
<Router>
<Redirect push to="/login" />
<Route path="/login" component={Login}/>
</Router>
}
)
const Login = () => (
<h1>Form Components</h1>
...
)
export default Example;
Another alternative is to handle this using Thunk-style asynchronous actions (which are safe/allowed to have side-effects).
If you use Thunk, you can inject the same history object into both your <Router> component and Thunk actions using thunk.withExtraArgument, like this:
import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
import { createBrowserHistory } from "history"
import { applyMiddleware, createStore } from "redux"
import thunk from "redux-thunk"
const history = createBrowserHistory()
const middlewares = applyMiddleware(thunk.withExtraArgument({history}))
const store = createStore(appReducer, middlewares)
render(
<Provider store={store}
<Router history={history}>
<Route path="*" component={CatchAll} />
</Router
</Provider>,
appDiv)
Then in your action-creators, you will have a history instance that is safe to use with ReactRouter, so you can just trigger a regular Redux event if you're not logged in:
// meanwhile... in action-creators.js
export const notLoggedIn = () => {
return (dispatch, getState, {history}) => {
history.push(`/login`)
}
}
Another advantage of this is that the url is easier to handle, now, so we can put redirect info on the query string, etc.
You can try still doing this check in your Render methods, but if it causes problems, you might consider doing it in componentDidMount, or elsewhere in the lifecycle (although also I understand the desire to stick with Stateless Functional Compeonents!)
You can still use Redux and mapDispatchToProps to inject the action creator into your comptonent, so your component is still only loosely connected to Redux.
This is my handle loggedIn. react-router v4
PrivateRoute is allow enter path if user is loggedIn and save the token to localStorge
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props => (localStorage.token) ? <Component {...props} /> : (
<Redirect
to={{
pathname: '/signin',
state: { from: props.location },
}}
/>
)
}
/>
);
}
Define all paths in your app in here
export default (
<main>
<Switch>
<Route exact path="/signin" component={SignIn} />
<Route exact path="/signup" component={SignUp} />
<PrivateRoute path="/" component={Home} />
</Switch>
</main>
);
Those who are facing issues in implementing this on react-router v4. Here is a working solution for navigating through the react app programmatically.
history.js
import createHistory from 'history/createBrowserHistory'
export default createHistory()
App.js OR Route.jsx. Pass history as a prop to your Router.
import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
<Route path="/test" component={Test}/>
</Router>
You can use push() to navigate.
import history from './history'
...
render() {
if (isLoggedIn) {
history.push('/test') // this should change the url and re-render Test component
}
// return login component
<Login />
}
All thanks to this comment: https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248
render(){
return (
<div>
{ this.props.redirect ? <Redirect to="/" /> :'' }
<div>
add here component codes
</div>
</div>
);
}
I would suggest you to use connected-react-router https://github.com/supasate/connected-react-router
which helps to perform navigation even from reducers/actions if you want.
it is well documented and easy to configure
I was able to use history within stateless functional component, using withRouter following way (needed to ignore typescript warning):
import { withRouter } from 'react-router-dom';
...
type Props = { myProp: boolean };
// #ts-ignore
export const MyComponent: FC<Props> = withRouter(({ myProp, history }) => {
...
})
import { useNavigate } from "react-router-dom"; //with v6
export default function Component() {
const navigate = useNavigate();
navigate.push('/path');
}
I had this issue and just solved it with the new useNavigate hook in version 6 of react-router-dom
I am trying to implement Google Analytics using the react-ga library which needs to fire whenever the route changes. I have the following setup in App.js:
import createBrowserHistory from 'history/createBrowserHistory';
...
const history = createBrowserHistory();
history.listen((location) => {
console.log('ANALYTICS CODE GOES HERE', location);
});
class App extends Component {
render() {
return (
<Provider store={...}>
<Router history={history}>
....
</Router>
</Provider>
);
}
}
export default App;
When I click on a NavLink throughout my app, the route changes and loads the appropriate component, but the history.listen() function never fires. However, if I use the browser's back/forward functionality it does fire.
<NavLink to="/account" activeClassName="active">ACCOUNT</NavLink>
How do I listen to route changes triggered by a NavLink?
Edit: further discussion taking place here: https://github.com/react-ga/react-ga/issues/122#issuecomment-316427527
Use a react-router <Route /> component as a wrapper for your tracking function - the route re-renders every time the location changes. For example:
import React from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import ReactGA from 'react-ga'
ReactGA.initialize('UA-00000000-1')
const tracker = ({location}) => {
// console.log('tracking', location.pathname)
ReactGA.set({page: location.pathname})
ReactGA.pageview(location.pathname)
return null
}
const App = (props) => (
<Router>
<div>
<Route render={tracker} />
...
</div>
</Router>
)