React Redirect when clicking button - javascript

I´m learning in react and practicing making a simple application to login and view messages sent.
I´ve read a lot about routing, links and redirect, but i couldn´t translate to my app.
I Would like to click in the "Login" button of a component and redirect to another component.
Here i have the principal component : App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
class Login extends Component {
state = {
loggedIn:false
};
loginHandle = () => {
this.setState({loggedIn:true});
}
render(){
return (
<div className="container d-flex h-100">
<div className="row align-self-center w-100">
<div className="col-6 mx-auto">
<div className="jumbotron">
<form name="form1">
<fieldset>
<legend>Chat App</legend>
<label for="UserName" className="col-form-label">Username</label>
<input type="text" className="form-control col-12" id="UserName"></input>
<label for="Password" className="col-form-label">Password</label>
<input type="text" className="form-control col-12" id="Password"></input>
<button type="button" value="log in" className="btn btn-secondary" onClick={this.loginHandle}>Login</button>
</fieldset>
</form>
<div style={{float:"right"}}>
<div className="login-help ">
Register - Forgot Password
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
I wrapped all the Links in a Navigation component
So, when i route /, it goes to the Login component
class Login extends Component {
state = {
loggedIn:false
};
loginHandle = () => {
this.setState({loggedIn:true});
}
render(){
return (
<div className="container d-flex h-100">
<div className="row align-self-center w-100">
<div className="col-6 mx-auto">
<div className="jumbotron">
<form name="form1">
<fieldset>
<legend>Chat App</legend>
<label for="UserName" className="col-form-label">Username</label>
<input type="text" className="form-control col-12" id="UserName"></input>
<label for="Password" className="col-form-label">Password</label>
<input type="text" className="form-control col-12" id="Password"></input>
<button type="button" value="log in" className="btn btn-secondary" onClick={this.loginHandle}>Login</button>
</fieldset>
</form>
<div style={{float:"right"}}>
<div className="login-help ">
Register - Forgot Password
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
Do i have to import routes and redirect in the Login component, or i have to mange all from the App component?
Sorry about this mess, but i don´t know how to continue
Thanks a lot. I really apreciatted in advance.

The simplest way for navigating to another route.
For example you can wrap your Forgot password like following:
<Link to="/forgotRoute">Forgot password?</Link>
Don't forget to add /forgotRoute handling into your Navigator config (where you routed / to your Login component).
Hope it helps.

The correct way for what you want i think it is. So follow me..
You need to use router. In my case i'm using react-router-dom.
First router App component, by default page its renders DefaultPage components and in DefaultPage when component mounted you can render client anywhere.
index.js looks like:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Route, Switch } from 'react-router-dom';
class DefaultPage extends Component {
state = {
autorized: false,
mounted: false,
}
componentDidMount = () => {
const { autorized } = this.state;
if (!autorized) {
this.props.history.push('/login');
return;
}
this.setState({
mounted: true,
});
}
render = () => {
if (!this.state.mounted) {
return (
<React.Fragment>
<p>Waiting...</p>
</React.Fragment>
)
}
return (
<React.Fragment>
<p>Hello...</p>
</React.Fragment>
)
}
}
class Login extends React.Component {
handleLogin = () => {
if (contidion) {
this.props.history.push('/');
}
}
render = () {
return (
<button onClick={this.handleLogin}>Click to login</button>
)
}
}
class App extends React.Component {
render = () {
return (
<Switch>
<Route exact path="/" component={DefaultPage} />
<Route path="/login" component={Login} />
<Route component={DefaultPage} />
</Switch>
)
}
}
ReactDOM.render(
<BrowserRouter >
<App />
</BrowserRouter>,
document.getElementById("root")
);

Related

reactjs preventDefault() is not preventing the page reload on form submit

EDIT: Events are not working at all, the onSubmit and onChange functions are not being called. I have another reactapp with similar form and onChange and onSubmit works OK there.
I have a form I dont want the page to refresh when I click on submit. I tried using preventDefault() but I didnt work. Even onChange is printing anything on console. This form is not on page, I am using React Router to point to='/new' and component={NewPost} (NewPost is in ./components/posts/form)
./components/posts/form.js:
import React, { Component } from "react";
import { connect } from "react-redux";
class NewPost extends Component {
state = {
title: "",
body: "",
status: 0,
};
onSubmit = (e) => {
e.preventDefault();
const post = e;
console.log(post);
};
onChange = (e) => {
console.log(e.target.value);
this.setState({
[e.target.name]: e.target.value,
});
};
render() {
const { title, body, status } = this.state;
return (
<div className="card card-body mt-4 mb-4">
<h2>New Post</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Title</label>
<input
type="text"
name="title"
value={title}
onChange={this.onChange}
className="form-control"
/>
</div>
<div className="form-group">
<label>Content</label>
<textarea
type="text"
name="body"
rows="15"
value={body}
onChange={this.onChange}
className="form-control"
/>
</div>
<div className="form-group">
<button className="btn btn-primary" type="submit">
Submit
</button>
</div>
</form>
</div>
);
}
}
export default NewPost;
App.js:
import React from "react";
import NavBar from "./components/layout/navbar";
import store from "./store";
import { Provider } from "react-redux";
import Dashboard from "./components/posts/dashboard";
import NewPost from "./components/posts/form";
import {
HashRouter as Router,
Route,
Switch,
Redirect,
} from "react-router-dom";
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Router>
<React.Fragment>
<div className="container">
<NavBar />
<Switch>
<Route exact path="/" component={Dashboard}></Route>
<Route exact path="/new" component={NewPost}></Route>
</Switch>
</div>
</React.Fragment>
</Router>
</Provider>
);
}
}
export default App;
Issue is not related to code. I created new react application and moved all my code now everything is working fine.

React Hide/Show Menu on Successful Login and Passing Information from one Component to a Component

Total Newbie in React and most of my learning is done through experimentation.
I have the following components:
App.js
import React, { Component } from 'react';
// Libraries and Utilities
import { BrowserRouter, Switch, Route } from 'react-router-dom';
// Components
import Layout from './components/layout/Layout';
import Home from './components/home/Home';
import Login from './components/login/Login';
class App extends Component {
static displayName = App.name;
render() {
return (
<BrowserRouter basename='/myapp>
<Layout>
<Switch>
<Route path="/" exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/admin' component={Admin} />
</Switch>
</Layout>
</BrowserRouter>
);
}
}
export default App;
Layout.js
import React, { Component } from 'react';
import NavMenu from '../navigation/NavMenu';
class Layout extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
<NavMenu />
</div>
<div className="main layout">
{this.props.children}
</div>
<div className="row">
<Footer />
</div>
</div>
);
}
};
export default Layout;
NavMenu.js
import React, { Component } from 'react';
import { NavLink } from "react-router-dom";
import logo from '../../assets/logo.svg';
class navigation extends Component {
constructor(props) {
super(props)
this.state = {
loggedIn: false
}
}
render() {
return (
<div className="row">
<nav className="navbar navbar-expand navbar-dark bg-primary fixed-top">
<a className="navbar-brand" href="/">
<img src={logo} width="250" height="70" alt="" />
</a>
<div className="collapse navbar-collapse">
<ul className="navbar-nav mr-auto">
<li className="nav-item" to={'/'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/'>Home</NavLink>
</li>
<li className="nav-item" to={'/admin1'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 1</NavLink>
</li>
<li className="nav-item" to={'/admin2'}>
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/admin1'>Admin 2</NavLink>
</li>
</ul>
<ul className="navbar-nav">
<li className="nav-item">
<NavLink exact={true} className="navbar-brand" activeClassName='active' to='/login'>
<i className="fa fa-sign-in" aria-hidden="true"></i>
</NavLink>
</li>
</ul>
</div>
</nav>
</div>
)
};
};
export default navigation;
Login .js
import React, { Component } from 'react';
class login extends Component {
constructor(props) {
super(props)
this.state = {
loginModel: {
UserName: '',
Password: ''
}
}
this.handleInputChange = this.handleInputChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleInputChange(event) {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState(prevState => ({
loginModel: {
...prevState.loginModel,
[name]: value
}
}))
}
handleSubmit(event) {
// At This Stage, I perform an API Call (via axios) and I get the Response Data.
const url = 'some url'
axios.post(url, this.state.loginModel).then((response) => {
if (response.status === 200) {
// Get token from response to be used in authenticated api calls.
const responseData = response.data
let authToken = responseData.token
console.log('authToken', authToken)
swal({
title: "My Application",
text: "Logon Successful.",
icon: "success"
}).then((value) => {
// Go to the Admin Home.
const path = '/admin'
this.props.history.push(path);
})
}
}, (err) => {
console.log(err.response)
const msg = err.response.data.message
const icon = err.response.data.icon
swal({
title: "My Application",
text: msg,
icon: icon
})
})
)
event.preventDefault();
}
componentDidMount() {
}
render() {
return (
<form className="form-signin" onSubmit={this.handleSubmit} >
<h3>Sign In</h3>
<div className="form-group">
<label>Username</label>
<input type="text" className="form-control" autoComplete="off"
id="input-username" name="UserName"
value={this.state.loginModel.UserName}
onChange={this.handleInputChange}
placeholder="Enter Username" />
</div>
<div className="form-group">
<label>Password</label>
<input type="password" className="form-control" autoComplete="off"
id="input-password" name="Password"
value={this.state.loginModel.Password}
onChange={this.handleInputChange}
placeholder="Enter Password" />
</div>
<button type="submit" className="btn btn-primary btn-block">Submit</button>
</form>
)
}
}
export default login;
Home.js
import React from 'react';
import { NavLink } from "react-router-dom";
const home = (props) => {
return (
<div className="container-fluid">
<div className="fill">
<div className="row">
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 1</h5>
<p className="card-text">
Details about Info 1
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-primary btn-block" to='/info1'>Start</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 2</h5>
<p className="card-text">
Details about Info 2
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-info btn-block" to='/info2'>Browse</NavLink>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="card">
<div className="card-body flex-fill">
<h5 className="card-title">Info 3</h5>
<p className="card-text">
Details about Info 3
</p>
</div>
<div className="card-footer">
<NavLink exact={true} className="btn btn-success btn-block" to='/info3'>View</NavLink>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default home;
My approach is quite simple. The application shows the Home component on initial load.
In the Navmenu, I have a link that navigates me to the Login screen.
In the Login screen, I have a login form where I am able to validate the user name and password via an API call.
I have multiple questions as I am still learning, but adding them here altogether as I feel it is all related.
Questions:
In my NavMenu component, I want to hide the admin1 and admin2 when on
initial load, and show it when the login is successful in the Login
component.
I want to prevent user from going to the route /admin1 and
/admin2 unless they are logged in. I am trying to read Protected
Routes but I am unable to get the hang of it as of yet.
In my Login screen, after successful login, one of the return value of the API
call is an API Key I can use for authorized calls. How can I make
that available such that I can access it from anywhere I perform an
API call.
I hope I provided enough context on what I am trying to achieve here. I know I need to brush up further my skills on how data communication between React happens.
Update: Been reading about Hooks, but I am unsure how to implement it here. Would I need to convert my JS files to use functional approach rather than class structure (ES6)?
Gracias.
I use redux for checking if use if logged in or not.
So when app start before show anything I check this.
and then I have privateRoute.
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function PrivateRoute({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin);
return (
<Route
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
{...props}
/>
);
}
export default PrivateRoute;
and define IsAuthenticated component to redirect home page if user is already logged in:
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { useSelector } from "react-redux";
function IsAuthenticated({ component: Component, ...props }) {
const isAuthenticated = useSelector(state => state.User.isLogin)
return (
<Route
{...props}
render={props =>
!isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location }
}}
/>
)
}
/>
);
}
export default IsAuthenticated;
and define my routes here if user must authenticated to see them:
<Router>
<Switch>
{privateRoutes.map(({ path, component: Component }, idx) => (
<PrivateRoute
key={idx}
exact
path={path}
component={() => (
<SideNav>
<Component />
</SideNav>
)}
/>
))}
<IsAuthenticated exact path="/login" component={LoginPage} />
</Switch>
</Router>
here I use SideNav in my pages, you can use redux state in your Navbar component and with checking that you can show or hide whatever you want.
Or you can define two layout for your two types of your pages.
If you don't want to use redux, you can define state in App.js and pass it to your component or use react context.
I hope I helped you in your question.

How to Redirect/go to the User Profile after login page in ReactJS

I am trying to Redirect to the User Profile page once the user is logged in with valid username and password
But when I click the Login button, it doesn't go to the User Profile (but it changes the url as intended (http://localhost:3000/instructor/banuka)
It should also display InstructorLoginFormComponent which it doesn't. When I click nothing happens but all I can see is still there is the login page
This is my InstructorLoginForm.jsx
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InstructorProfile from "./instructor-profile";
import InstructorLoginFormComponent from "./instructor-login-form-component";
export default class InstructorLoginForm extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onChangePassword = this.onChangePassword.bind(this);
this.handleOnClick = this.handleOnClick.bind(this);
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onChangePassword(e) {
this.setState({
password: e.target.value
});
}
handleOnClick(e) {
e.preventDefault();
const path = `/instructor/${this.state.username}`;
this.props.history.push(path);
}
render() {
return (
<Router>
<Switch>
<Route
exact
path="/login"
component={props => (
<InstructorLoginFormComponent
{...props}
username={this.state.username}
password={this.state.password}
handleOnClick={this.handleOnClick}
onChangeUsername={this.onChangeUsername}
onChangePassword={this.onChangePassword}
/>
)}
/>
<Route
path={"/instructor/:instructorId"}
component={InstructorProfile}
/>
</Switch>
</Router>
);
}
}
This is the InstructorLoginFormComponent.jsx
import React, { Component } from "react";
import { Link } from "react-router-dom";
export default class InstructorLoginFormComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="container h-100" style={{ marginTop: 100 }}>
<div className="d-flex justify-content-center h-100">
<div className="user_card bg-dark">
<div className="d-flex justify-content-center">
</div>
<div
className="d-flex justify-content-center form_container"
style={{ marginTop: 0 }}
>
<form>
<div className="input-group mb-3">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-user" />
</span>
</div>
<input
value={this.props.username}
onChange={this.props.onChangeUsername}
type="text"
name="username"
className="form-control input_user"
placeholder="username"
/>
</div>
<div className="input-group mb-2">
<div className="input-group-append">
<span className="input-group-text bg-info">
<i className="fa fa-lock" />
</span>
</div>
<input
value={this.props.password}
onChange={this.props.onChangePassword}
type="password"
name="password"
className="form-control input_user"
placeholder="password"
/>
</div>
<div className="form-group">
<div className="custom-control custom-checkbox">
<input
type="checkbox"
className="custom-control-input"
id="customControlInline"
/>
<label
className="custom-control-label"
htmlFor="customControlInline"
style={{ color: "#ffffff" }}
>
Remember me
</label>
</div>
</div>
</form>
</div>
<div className="d-flex justify-content-center mt-3 login_container">
<Link
to={`/instructor/${this.props.username}`}
type="button"
className="btn login_btn bg-info"
>
Login
</Link>
</div>
</div>
</div>
</div>
);
}
}
And this is the InstructorProfile.jsx
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
export default class InstructorProfile extends Component {
render(){
return(
<div>
<h1>Welcome to the profile</h1>
</div>
);
}
}
Can someone please tell me where I have went wrong and suggest me a good way to redirect after login validation?
Resolved As Is
The problems you're experiencing are likely related to your router not being configured correctly. If you want your InstructorLoginFormComponent to be rendered on path /, you have to put it inside the route like below. You cannot just pass the reference to the component since you need to pass it the username, password, etc props. You should remove it from anywhere else in your render function since you only want it to render when the path is /. I also changed your instructor path to use :id. When you want to specify a url parameter, you need to use the syntax /<my_url>:<my_variable_name>. It's important to put the / out front of all your paths because it's a relative path if you don't.
New Router Component
<Router>
<Switch>
<Route exact path="/login" render={props => (
<InstructorLoginFormComponent
{...props}
username = { this.state.username }
password = { this.state.password }
handleOnClick = { this.handleOnClick }
onChangeUsername = { this.onChangeUsername }
onChangePassword = { this.onChangePassword }
/>
)} />
<Route path={"/instructor/:instructorId"} component={InstructorProfile} />
</Switch>
</Router>
Updated handleOnClick
handleOnClick(e) {
e.preventDefault();
const path = `/instructor/${this.state.username}`;
this.props.history.push(path);
}
Updated Login Button
<Link
to={`/instructor/${this.props.username}`}
type="button"
className="btn login_btn bg-info"
>
Login
</Link>
Recommendation Regarding Login
It's important to note that you aren't actually checking the username and password against something on the server. I'm not sure if this is your test code, or if you intend to implement something with REST. However, you should use a button instead of a link that calls a function on click that sends the username and password to the server. From there, it would return if the credentials matched and whether the user would be able to login or not. Then, you would use
this.props.history.push(`instructor/${this.state.username}`);
to forward the user to the instructor profile page. But you would only want to do that after you have checked their credentials. You would not use a Link component to perform those actions. I put an example below.
Example login button
<button
type="button"
className="btn login_btn bg-info"
onClick={this.props.handleOnClick}
>
Login
</button>
New handleOnClick
handleOnClick = async (e) => {
e.preventDefault();
//pseudo-code below
const user = await checkUserCredentialsAndGetUserObject(this.state.username, this.state.password);
if(user.response === 'success') {
this.setState({ user });
this.props.history.push(`/instructor/${this.state.username}`);
} else {
flashMessage('The user credentials you entered were incorrect.');
}
}
Ok, I'm not exactly sure what you're asking, but I think I know where you're going wrong.
First of all, when you use the exact keyword on a Route, it will literally only show when the url matches. So if you want the LoginFormComponent to show in addition to another, you need to remove the exact keyword.
Next, for dynamically rendering profile pages, you are not following how React Router works.
This tutorial gives a good overview: https://tylermcginnis.com/react-router-url-parameters/
The short of it is, for the Profile page, the path should be
<Route path='/instructor/:username' component={InstructorProfile} />
Then, in the profile component, set the initial state by accessing the username in the URL with
this.state = {
user: props.match.params.username
}
The question is a little vague, but I think this will help with what you're trying to do. Let me know if something is unclear.

Routing in ReactJS. URL is displayed but component is not rendered

I have the following piece of code in my parent component:
class App extends Component {
render() {
return(
<Router>
<div>
<Route exact path='/' component={Main} />
<Route path="/login" component={Login} />
</div>
</Router>
);
}}
And this in Main component:
import React, { Component } from "react";
import {BrowserRouter as Router, Route, Link } from 'react-router-dom'
class Main extends Component {
render() {
return (
<Router>
<section className="section main">
<div className="container">
<div className="main-titles-container">
<div className="main-titles">
<div className="yellow-square"></div>
<h1>Title</h1>
<p>
Introduction
</p>
<div className="button-container">
<Link to='/login' className="btn select bg-yellow" id="buyer">Next</Link>
</div>
</div>
</div>
</div>
</section>
</Router>
);
}
}
export default Main;
Login:
import React, { Component } from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
email: "",
cellphone: ""
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
const target = e.target;
this.setState({
[target.name]: target.value
});
}
handleSubmit(e) {
e.preventDefault();
console.log(this.state);
}
render() {
return (
<section className="section">
<div className="container center center-xy">
<h1 className="title center-self">Title</h1>
<h1 className="title center-self">Log in</h1>
<div className="form-container">
<form onSubmit={this.handleSubmit}>
<label htmlFor="email">Email</label>
<input type="text" name="email" id="email" onChange={this.handleChange} defaultValue="" required/>
<label htmlFor="cellphone">Cell phone</label>
<input type="text" name="cellphone" id="cellphone" defaultValue="" onChange={this.handleChange} required/>
<button className="bg-yellow center-self" type="submit">Ok</button>
</form>
</div>
</div>
</section>
);
}
}
export default Login;
On click I want to be redirected to Login page, but the problem is that when i click on that 'button' the URL is changed to '/login', but the corresponding component isn't rendered. However, if I refresh the page with that '/login' url the component is rendered.
Thanks for any help in advance!
EDIT: I'm not using PureComponent and wrapping exports in withRouter doesn't solve my problem too.
You should only have the top-level component (in your case, App) rendering the Router component. All of the components under that (ex. Main) should not have a Router in the render function. They will inherit the parent's Router. You can still use Link or Route components inside of the child components and they will navigate the parent Router.

Components not re-rendering on route change - React HashRouter

I've got a problem with react and react-router.
When I click on a link (in my example contact in Footer.js), the url changes, but the desired component Location is not shown. When I refresh the site then, the correct component is displayed.
App.js:
import React, { Component } from 'react';
import { BrowserRouter as Router, HashRouter, Route, Link } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.css';
import Footer from './Footer.js';
import Navigation from './Navigation.js';
import Background from './Background.js';
import Home from './Home.js';
import Products from './Products.js';
import Industries from './Industries.js';
import Partner from './Partner.js';
import Location from './Location.js';
import MeetUs from './MeetUs.js';
import ScrollUp from './ScrollUp.js';
import Divider from './Divider.js';
import Country from './Country.js';
import Language from './Language.js';
import Waypoint from 'react-waypoint';
import $ from "jquery";
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentLanguage: 'en',
currentBU: '',
currentIndustry: '',
showMainProductGroups: false,
currentCountry: 'group',
countryObject: Country['group'],
contacts: [],
mainProductGroups: [],
};
}
handleCountryChange() {
//...
}
handleLanguageChange() {
//...
}
handleBUChange() {
//...
}
render() {
const routes = [
{
path: '/',
exact: true,
components: () =>
<div>
<Home key="home" currentLanguage={this.state.currentLanguage} />
</div>,
},
{
path: '/contact',
exact: true,
components: () => <Location key="locations" currentLanguage={this.state.currentLanguage} country={this.state.countryObject} contacts= {this.state.contacts} onCountryChange={this.handleCountryChange.bind(this)} />
},
]
return (
<HashRouter>
<div>
<Background />
<div id="wrap">
<div id="main" className="container clear-top marginBottom50px">
<div id="content">
<Navigation key="navBar" currentLanguage={this.state.currentLanguage} onLanguageChange={this.handleLanguageChange.bind(this)} onBUChange={this.handleBUChange.bind(this)} onCountryChange={this.handleCountryChange.bind(this)} />
{
routes.map((route, index) => (
<Route key={index} path={route.path} exact={route.exact} component={route.components} />
))
}
</div>
</div>
</div>
<Footer key="footer" currentLanguage={this.state.currentLanguage} />
<ScrollUp key="scrollUp" />
</div>
</HashRouter>
);
}
}
export default App;
Home.js:
import React, { Component } from 'react';
import $ from "jquery";
import { Link } from 'react-router-dom';
import {withRouter} from 'react-router';
import Language from './Language.js';
import locations from './locations.jpg';
import locationLegend from './locationLegend.jpg';
require('bootstrap')
class Home extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div className="container marginTop50px marginBottom50px area">
<div className="row">
<div className="col-12 text-center animDelay2 fadeInDown animated">
<h1>International Distribution of Specialty Chemicals</h1>
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center animDelay2 fadeInUp animated">
{Language[this.props.currentLanguage].homeStartText}
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center">
<img src={locations} className="img-fluid" alt="Locations" />
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center">
<img src={locationLegend} className="img-fluid" alt="Locations" />
</div>
</div>
</div>
);
}
}
export default withRouter(Home);
Location.js:
import React, { Component } from 'react';
import $ from "jquery";
import { Link } from 'react-router-dom';
import Language from './Language.js';
import Country from './Country.js';
import ContactPerson from './ContactPerson.js';
import locations from './locations.png';
import phone from './phoneBlack.svg';
import fax from './faxBlack.svg';
import email from './emailBlack.svg';
import {withRouter} from 'react-router';
require('bootstrap');
class Location extends Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('Country change:' + this.props.country.key);
$('#selectCountry').val(this.props.country.key); //name['en']
}
onCountryChange() {
let countryName = this.refs.country.value;
this.props.onCountryChange(countryName);
}
render() {
return (
<div className="container marginTop50px marginBottom50px area" id="locations">
<div className="row">
<div className="col-12 text-center">
<h2>{Language[this.props.currentLanguage].locations}</h2>
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center">
<div className="form-group">
<select id="selectCountry" className="form-control" ref="country" onChange={this.onCountryChange.bind(this)}>
<option defaultValue>{Language[this.props.currentLanguage].selectLocation.toUpperCase()}</option>
{
Object.keys(Country).map((countryKey) => {
const country = Country[countryKey];
return (
<option value={countryKey} key={"loc" + countryKey}>{country.name[this.props.currentLanguage].toUpperCase()}</option>
);
})
}
</select>
</div>
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center">
{this.props.country.name[this.props.currentLanguage].toUpperCase()}
<br />
<address>
<span dangerouslySetInnerHTML={{__html: this.props.country.address}}></span>
<br />
<br />
<img src={phone} alt="Anrufen" className="phoneMain"></img><span> </span>
<a href={this.props.country.phoneHTML}>{this.props.country.phone}</a>
<br />
<img src={fax} alt="Fax" className="phoneMain"></img><span> </span>
<a href={this.props.country.faxHTML}>{this.props.country.fax}</a>
<br />
<img src={email} alt="Email" className="emailMain"></img><span> </span>
<a href={"mailto://" + this.props.country.email}>{this.props.country.email}</a>
</address>
</div>
</div>
<div className="row marginTop25px">
<div className="col-12 text-center">
{Language[this.props.currentLanguage].vatRegistrationNumber + ": " + this.props.country.vatNo}
<br />
{Language[this.props.currentLanguage].registrationOffice + ": "}
<span dangerouslySetInnerHTML={{__html: this.props.country.registrationOffice}}></span>
</div>
</div>
<div className="row marginTop50px">
<div className="col-12 text-center">
<h3>{Language[this.props.currentLanguage].contact}</h3>
</div>
</div>
<div className="row">
{
this.props.contacts.map((contact) => {
return (
<div className="col-12 col-sm-12 col-md-12 col-lg-6 text-center">
<ContactPerson contact={contact} key={"contact" + contact.id} />
</div>
);
})
}
</div>
</div>
);
}
}
export default withRouter(Location);
Footer.js:
import React, { Component } from 'react';
import $ from "jquery";
import { Link } from 'react-router-dom';
import {withRouter} from 'react-router';
import Language from './Language.js';
import phone from './phoneWhite.svg';
import fax from './faxWhite.svg';
require('bootstrap');
class Footer extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<footer className="footer">
<div className="container-fluid borderTop1px footerLayout">
<div className="row">
<div className="col-3">
<address>
<small>
Some text
</small>
</address>
</div>
<div className="col-6 text-center">
<div className="row">
<div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
<small>{Language[this.props.currentLanguage].download}</small>
</div>
<div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
<Link to="/imprint" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].imprint}</small></Link>
</div>
<div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
<Link to="/contact" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].contact}</small></Link>
</div>
<div className="col-12 col-sm-12 col-md-12 col-lg-3 text-center">
<Link to="/termsAndConditions" className="nav-link footerLink"><small>{Language[this.props.currentLanguage].termsAndConditions}</small></Link>
</div>
</div>
</div>
<div className="col-3">
<ul className="list-inline">
<li>
<img src={phone} alt="Anrufen" className="phone"></img> <small><a className="footerLink" href="tel:+49">+49</a></small>
</li>
<li>
<img src={fax} alt="Fax" className="phone"></img> <small><a className="footerLink" href="tel:+49">+49</a></small>
</li>
</ul>
</div>
</div>
</div>
</footer>
);
}
}
export default withRouter(Footer);
What I'm doing wrong? Why it is not working, when I click on a link?
Got it working now.
I needed to change <HashRouter> to <Router>. Then it works fine.
UPDATE:
This solution solves the problem, but then there is a different problem: When I have navigated and refresh the page, then an error (404) is thrown, because there is of course no such a page on the server.
I need to get the HashRouter work.
When you declare your routes in App.js, you should pass the props to the component:
components: props => <Location {...props} <insert other props> />
You should stick to the <Router> solution as having unnecessary hash in the url is ugly.
When I have navigated and refresh the page, then an error (404) is thrown, because there is of course no such a page on the server.
To resolve this, you need to set up a redirect to redirect all requests to the base url for the React app to handle (the url displayed will be preserved).
On Netlify, you can create a _redirects file in your public folder with the content:
/* /index.html 200
On AWS S3, the redirect rules can be set in S3 or CloudFront, see the answers here.
For Google Cloud bucket, see this.
For Github pages, see this.
In your Route component you use component prop to pass the Location component (instead of render or children props available on Route) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop.However in your case it seems you are using it for no reason so you should just pass the component and not an inline function that returns it like so :
const routes = [
{
path: '/',
exact: true,
components: <Home key="home" currentLanguage={this.state.currentLanguage}/>
},
{
path: '/contact',
exact: true,
components: <Location key="locations" currentLanguage={this.state.currentLanguage} country={this.state.countryObject} contacts= {this.state.contacts} onCountryChange={this.handleCountryChange.bind(this)} />
},
]
Make your routes use Component as below
import {IndexRoute, Route} from 'react-router';
<Route component={App}>
<Route path='/locations' component={LocationComponent}/>
</Route>
This is what I am doing in my current project without using HashRouter.
Currently, When you do
<Route key={index} path={route.path} exact={route.exact} component={route.components} />
I don't think {route.components} treats it as a component.
Could be a problem with withRouter().
Have you seen this?
https://github.com/ReactTraining/react-router/issues/5037

Categories