This is my index.js page
import React from 'react';
import ReactDOM from 'react-dom';
import Login from './Login';
import Dashboard from './Dashboard';
import { BrowserRouter as Router, Route} from 'react-router-dom';
import './css/bootstrap.min.css';
import './css/font-awesome.min.css';
import './css/style.css';
import { createHistory, useBasename } from 'history'
const history = useBasename(createHistory)({
basename: '/'
})
ReactDOM.render((
<Router history={history}>
<div>
<Route path="/" component={Login} />
<Route path="dashboard" component={Dashboard} store={Dashboard} />
<Route exact path="login" component={Login} store={Login} />
</div>
</Router>
),
document.getElementById('root')
);
This is my login page. But clicking on the button doesn't redirect to the corresponding component.
import React, { Component } from 'react';
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
//this.props.router.push('/dashboard'); // Its was not working
this.props.history.push('dashboard'); //Its working for me
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In your case this.props.router would be undefined. Here's a rough solution that I made. Reading the comments in the code will help.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom'; // add this import
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : '',
redirectToReferrer: true // when you're checking if the user is authenticated you have to keep this false
};
}
// componentWillReceiveProps(nextProps) {
// if ( put your authentication logic here ) {
// this.setState({ redirectToReferrer: true });
// }
// }
login(){
this.props.history.push('/dashboard');
}
render() {
const from = { pathname: '/dashboard' };
const { redirectToReferrer } = this.state; // redirectToReferrer is true in the initial state
if (redirectToReferrer) { // if true the user will be redirected to /dashboard
return <Redirect to={from} />;
}
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In React 16 and above you can use Redirect from 'react-router-dom'
import { Redirect } from 'react-router-dom'
Define state in your component
this.state = {
loginStatus:true
}
than in your render method
render () {
if(this.state.loginStatus){
return <Redirect to='/home' />
}
return(
<div> Please Login </div>
)
}
Make use of withRouter frun react-router to inject router as a prop to your login component
import React, { Component } from 'react';
import {withRouter} from 'react-router'
import $ from 'jquery';
class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
this.props.history.push('/dashboard');
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Login)
Related
I am trying to implement this feature in my React JS app where if I login successfully, the UI would display the Logout button in the navbar. But if I click on the Logout, I would be logged out from the main UI and redirected to the Login Page where the navbar won't have any Logout Button. Currently, when I log in to the main UI successfully, then I have to refresh the browser tab to show the logout button. It does not appear automatically once I log in successfully.
This is my header Component:
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
The isUserLoggedIn is a boolean value that is retrieved from the session storage. If isUserLoggedIn is true then the Logout button would be displayed on the Navbar.
const isUserLoggedIn = sessionStorage.getItem("authenticatedUser");
The AuthenticationService.js file is:
import React, { Component } from "react";
class AuthenticationService extends Component {
registerSuccessfulLogin(username, password) {
console.log("Login Successful");
sessionStorage.setItem("authenticatedUser", username);
console.log(sessionStorage.getItem("authenticatedUser"));
}
isUserLoggedIn() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) {
return false;
} else {
return true;
}
// return true;
}
logout() {
sessionStorage.removeItem("authenticatedUser");
}
getLoggedInUserName() {
let user = sessionStorage.getItem("authenticatedUser");
if (user === null) return "";
return user;
}
}
export default new AuthenticationService();
The App.js component is:
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
function App() {
return (
<div className="App">
<HeaderComponent />
<Router>
<Routes>
<Route path="/" element={<LoginComponent />}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
I am not sure why do I have to refresh the Tab to show the Logout button on to the NavBar.
EDIT
I have added the Login component for further reference:
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
Your header component is a stateless component, it has neither props nor internal state, so it is only rendered once with the initial value of isUserLoggedIn.
If you want the header component to react to the login status, it needs to be notified in some way that the value has changed. The easiest way to do so is to store this information in the state of your App component, then passing it down as a prop to the HeaderComponent.
// App.js
import "./App.css";
import DropDownMenu from "./components/DropdownMenu/DropDownMenu";
import HeaderComponent from "./components/Header/HeaderComponent";
import LoginComponent from "./components/Login/LoginComponent";
import {
BrowserRouter as Router,
Routes,
Route,
useParams,
Link,
} from "react-router-dom";
import "./styles.css";
import "./loginStyle.css";
import "./Header.css";
import ErrorComponent from "./components/search-options/ErrorComponent";
import AuthenticatedRoute from "./components/DropdownMenu/AuthenticatedRoute";
import AuthenticationService from "../Login/AuthenticationService";
function App() {
const [isUserLoggedIn, setIsUserLoggedIn] = useState(AuthenticationService.isUserLoggedIn()) // use the session storage to get the initial state's value
function onLoginSuccessful() {
setIsUserLoggedIn(true); // update the state to notify React the value has changed
}
return (
<div className="App">
<HeaderComponent isUserLoggedIn={isUserLoggedIn} /> {/* pass down the state value as a prop */}
<Router>
<Routes>
<Route path="/" element={<LoginComponent onLoginSuccessful={onLoginSuccessful}/>}></Route>
{/* <Route path="/login" element={<Navigate to="/LoginComponent" />} /> */}
<Route path="/login" default element={<LoginComponent onLoginSuccessful={onLoginSuccessful} />}></Route>
<Route
path="/pst"
element={
<AuthenticatedRoute>
<DropDownMenu />
</AuthenticatedRoute>
}
></Route>
<Route path="*" element={<ErrorComponent />}></Route>
</Routes>
</Router>
</div>
);
}
export default App;
// HeaderComponent.js
import React, { Component } from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import AuthenticationService from "../Login/AuthenticationService";
class HeaderComponent extends Component {
render() {
const isUserLoggedIn = this.props.isUserLoggedIn; // retrieve the value from the props
console.log(isUserLoggedIn);
return (
<nav className="navbar navbar-expand-lg ">
<Router>
<div className="container-fluid">
<a className="navbar-brand" href="#">
<span className="header-title">TODO APP</span>
</a>
<ul className="navbar-nav d-flex flex-row ms-auto me-3">
{isUserLoggedIn && (
<Link
to="/login"
onClick={() => {
window.location.href = "/login";
}}
>
{" "}
<button
className="btn btn-success logout-button"
onClick={AuthenticationService.logout}
>
Logout
</button>
</Link>
)}
</ul>
</div>
</Router>
{" "}
</nav>
);
}
}
export default HeaderComponent;
Note that you also have to pass a callback to LoginComponent to be called once the user successfully logs in. Using state updates, React gets notified that the value of isUserLoggedIn has changed and will re-render the components that depend on this value, including HeaderComponent.
EDIT: I updated the implementation of LoginComponent with the callback I mentionned
// LoginComponent.js
import axios from "axios";
import { data } from "jquery";
import React, { Component } from "react";
import { useNavigate } from "react-router";
import App from "../../App";
import HeaderComponent from "../Header/HeaderComponent";
import GetUserIp from "../tracking/GetUserIp";
import TrackLoginActivity from "../tracking/TrackLoginActivity";
import AuthenticationService from "./AuthenticationService";
class LoginComponent extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
ipAddress: "",
hasLoginFailed: false,
isUserLoggedIn: false,
};
this.handleCredentialChange = this.handleCredentialChange.bind(this);
this.submitLogin = this.submitLogin.bind(this);
}
handleCredentialChange(event) {
console.log(event.target.name);
this.setState({ [event.target.name]: event.target.value });
}
submitLogin(event) {
event.preventDefault();
var session_url =
"login check api url";
GetUserIp.retrieveIpAddress().then((response) => {
this.setState({ ipAddress: response.data.ip });
});
console.log(this.state.ipAddress);
axios
.post(
session_url,
{},
{
auth: {
username: this.state.username,
password: this.state.password,
},
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
}
)
.then((response) => {
console.log("Authenticated");
console.log(this.props);
AuthenticationService.registerSuccessfulLogin(
this.state.username,
this.state.password
);
// add this line to your `LoginComponent` so that
// onLoginSuccessul is called when user is logged in
this.props.onLoginSuccessful();
this.props.navigate(`/pst`);
//track user login activity into the DB Entity, smart_tool_login_logs
TrackLoginActivity.trackSuccessfulLogin(
this.state.username,
this.state.ipAddress
);
})
.catch((error) => {
console.log("Error on autheication");
this.setState({ hasLoginFailed: true });
});
}
render() {
return (
<div className="login-app">
<form action="" className="login-form" onSubmit={this.submitLogin}>
<div className="container">
<input
type="text"
placeholder="username"
name="username"
className="username-value"
maxLength={30}
autoComplete="on"
value={this.state.username}
onChange={this.handleCredentialChange}
/>
<input
type="password"
placeholder="password"
name="password"
className="password-value"
maxLength={30}
autoComplete="on"
value={this.state.password}
onChange={this.handleCredentialChange}
/>
{this.state.hasLoginFailed && (
<div className="login-fail-message">
Invalid username/password
</div>
)}
<div className="login-btn"></div>
<button className="btn btn-success login-btn" type="submit">
Login
</button>
</div>
</form>
</div>
);
}
}
function WithNavigate(props) {
let navigate = useNavigate();
return <LoginComponent {...props} navigate={navigate} />;
}
export default WithNavigate;
I am using material-UIs text fields and want to get the value from the user's input. Right now I am just trying to log the value to the console, so I can see it is getting the value but, it is logging blank. How can I get the Input from the text field?
The Input cards are a component with the text field along with a few other design things.
import "./StartPage.scss";
import React, { Component } from "react";
import InputCard from '../components/InputCard';
import {BrowserRouter as Router, Switch, Route, Link} from 'react-router-dom';
import ResultsPage from '../pages/ResultsPage';
import InputToFormula from "../components/InputToFormula";
import PropTypes from 'prop-types';
import { evaluate } from "mathjs";
import * as math from "mathjs";
import { tsConstructorType } from "#babel/types";
class StartPage extends Component {
constructor(props) {
super(props);
this.state = {
setBots: "",
setEmployees: "",
setSalary: "",
setTime: ""
};
};
handleBots = event => {
this.setState({ setBots: event.target.value});
};
handleEmployees = event => {
this.setState({ setEmployees: event.target.value});
};
handleSalary = event => {
this.setState({ setSalary: event.target.value});
};
handleTime = event => {
this.setState({ setTime: event.target.value});
};
logValue = () => {
console.log(this.state.setBots);
};
render(){
return (
<div className="container">
<div className="header-container">
<h2> </h2>
<h1>Return on Investment Calculator</h1>
<h2> </h2>
</div>
<form>
<div class="inputs input-group">
<InputCard onEvent={this.handleBots} id="Bots" icon="robot" label="Number of Processes" />
<InputCard onEvent={this.handleEmployees} id="Employees" icon="users" label="Number of FTE's" />
<InputCard onEvent={this.handleSalary} id="Salary" icon="dollar-sign" label="Average Salary" />
<InputCard onEvent={this.handleTime} id="Time" icon="clock" label="Average Time (%)" />
</div>
<Router>
<div>
<h1> </h1>
<Link to='/ResultsPage'><button onClick={this.logValue} type="button"
class="btn btn-outline-success submit-button btn-lg">CALCULATE</button></Link>
</div>
<Switch>
<Route path="/ResultsPage" exact>
<ResultsPage />
</Route>
</Switch>
</Router>
</form>
</div>
);
}
}
export default StartPage;
Use onChange instead of onEvent, here you can read more about it
I'm making a react application and whenever I search for something(eg cat) on the homepage, the url changes to search/cat and the forward, backward button work normally & help me switch between the homepage and the cat search page ...but when i search for something again (eg rat) after(homepage->cat) so the url changes to search/rat? and now when i press the back button the url changes to search/rat and i'm on the same page then if i press back button again the url becomes search/cat but the page still has the results of the rat search and if i press back again ,the homepage appears..why is this happening?I think it's because of the ? that appears at the end of the url..Please help
after searching cat
after searching for rat
after pressing the back button
after pressing the back button
after pressing the back button
This is the code of the search bar
import React, { Component } from "react";
import "./styles/searchBar.scss";
import "font-awesome/css/font-awesome.min.css";
import { withRouter } from "react-router-dom";
import SearchForm from "./SearchForm";
import { connect } from "react-redux";
import { fetchRandomPhotos } from "../redux/actions/randomPhotoAction";
class SearchBar extends Component {
state = {
searchQuery: "",
};
componentDidMount() {
this.props.fetchRandomPhotos();
}
handleChange = (event) => {
this.setState({ searchQuery: event.target.value });
};
handleSubmit = (event) => {
//event.preventDefault();
this.props.history.push(`/search/${this.state.searchQuery}`);
};
handleProfile = () => {
this.props.history.push(`/public/${this.props.photo.user.username}`);
};
render() {
const { photo } = this.props;
return !photo ? (
<div className="search-bar-container">
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
</div>
) : (
<div
className="search-bar-container"
style={{ backgroundImage: `url("${photo.urls.full}")` }}
>
<div className="black-layer"></div>
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
<div className="picture-info">
<div className="photographer">
<p onClick={this.handleProfile}>
<strong>Photo</strong> by {""}
<strong>{photo.user.name}</strong>
</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
photo: state.randomPhotoState.photo,
};
};
export default connect(mapStateToProps, { fetchRandomPhotos })(
withRouter(SearchBar)
);
This is the App.js
import React from "react";
import Navbar from "./components/Navbar";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import Home from "./pages/Home";
import LoginPage from "./pages/LoginPage";
import ProfilePage from "./pages/ProfilePage";
import SearchPage from "./pages/SearchPage";
import PublicUserProfilePage from "./pages/publicUserProfilePage";
import MobileNavigation from "./components/MobileNavigation";
import AboutPage from "./pages/AboutPage";
function App() {
return (
<BrowserRouter>
<Navbar />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={LoginPage} />
<Route exact path="/profile" component={ProfilePage} />
<Route exact path="/search/:searchQuery" component={SearchPage} />
<Route exact path="/about" component={AboutPage} />
<Route
exact
path="/public/:username"
component={PublicUserProfilePage}
/>
<Redirect to="/" />
</Switch>
<MobileNavigation />
</BrowserRouter>
);
}
export default App;
search form component
import React, { Component } from "react";
export class SearchForm extends Component {
render() {
const { onSubmit, onChange } = this.props;
return (
<form className="search-form" onSubmit={onSubmit}>
<input
type="text"
placeholder="Search free high-resolution photos"
onChange={onChange}
/>
<button type="submit">
<i className="fa fa-search"></i>
</button>
</form>
);
}
}
export default SearchForm;
import React, { Component } from "react";
import "./styles/searchBar.scss";
import "font-awesome/css/font-awesome.min.css";
import { withRouter } from "react-router-dom";
import SearchForm from "./SearchForm";
import { connect } from "react-redux";
import { fetchRandomPhotos } from "../redux/actions/randomPhotoAction";
class SearchBar extends Component {
state = {
searchQuery: "",
};
componentDidMount() {
this.props.fetchRandomPhotos();
}
handleChange = (event) => {
this.setState({ searchQuery: event.target.value });
};
handleSubmit = (event) => {
event.preventDefault();
if (this.state.searchQuery) {
this.props.history.push(`/search/${this.state.searchQuery}`);
}
};
handleProfile = () => {
this.props.history.push(`/public/${this.props.photo.user.username}`);
};
render() {
const { photo } = this.props;
return !photo ? (
<div className="search-bar-container">
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
</div>
) : (
<div
className="search-bar-container"
style={{ backgroundImage: `url("${photo.urls.full}")` }}
>
<div className="black-layer"></div>
<div className="search-bar-area">
<div className="about-foto-fab">
<h1>Foto-Fab</h1>
<p>The internet's source of freely-usable images.</p>
<p>Powered by creator everywhere</p>
</div>
<SearchForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
</div>
<div className="picture-info">
<div className="photographer">
<p onClick={this.handleProfile}>
<strong>Photo</strong> by {""}
<strong>{photo.user.name}</strong>
</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
photo: state.randomPhotoState.photo,
};
};
export default connect(mapStateToProps, { fetchRandomPhotos })(
withRouter(SearchBar)
);
I am new to react and trying below link to get started.
https://jasonwatmore.com/post/2018/09/11/react-basic-http-authentication-tutorial-example
But, my screen is not showing any thing and there is not such error on CLI after npm start.
Below is index.js.
import React from 'react';
import { render } from 'react-dom';
import { App } from './App/App.js';
// setup fake backend
import { configureFakeBackend } from './_helpers/fake-backend.js';
configureFakeBackend();
render(
<App />,
document.getElementById('app')
);
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { PrivateRoute } from '../_components/PrivateRoute.js';
import { HomePage } from '../HomePage/Homepage.js';
import { LoginPage } from '../LoginPage';
class App extends React.Component {
render() {
return (
<div className="jumbotron">
<div className="container">
<div className="col-sm-8 col-sm-offset-2">
<Router>
<div>
<PrivateRoute path="/" exact component={HomePage} />
<Route path="/login" exact component={LoginPage} />
</div>
</Router>
</div>
</div>
</div>
);
}
}
export { App };
It is just opening a blank half opened screen.
Below is CLI screen shot.
Below are home and login.js code.
import React from 'react';
import { Link } from 'react-router-dom';
import { userService } from '../_services/user.service.js';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {},
users: []
};
}
componentDidMount() {
this.setState({
user: JSON.parse(localStorage.getItem('user')),
users: { loading: true }
});
userService.getAll().then(users => this.setState({ users }));
}
render() {
const { user, users } = this.state;
return (
<div className="col-md-6 col-md-offset-3">
alert("I am 2nd here");
<h1 >Hi {user.firstName}!</h1>
<p>You're logged in with React & Basic HTTP Authentication!!</p>
<h3>Users from secure api end point:</h3>
{users.loading && <em>Loading users...</em>}
{users.length &&
<ul>
{users.map((user, index) =>
<li key={user.id}>
{user.firstName + ' ' + user.lastName}
</li>
)}
</ul>
}
<p>
<Link to="/login">Logout</Link>
</p>
</div>
);
}
}
export { HomePage };
And output screen is :
I'm new to React (but I already made a simple app with ReactNative). I made a simple web app with few components to make a user login. The problem is that it must support multilang and I can't totally understand how to use redux in order to change the system language from the child component 'Menu' to all the components that are or will be loaded inside the app.
Here are the main components:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<App />,
document.getElementById('root')
);
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
import Globals from './globals/globals.js';
import './assets/css/main.css';
import Menu from './components/Menu.js';
import Footer from './components/Footer.js';
import Loading from './components/Loading.js';
import Login from './pages/Login.js';
import Home from './pages/Home.js';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
accessToken: "",
isLogged: undefined,
}
}
componentDidMount(props) {
// Get access token if stored
let accessToken = localStorage.getItem('accessToken');
if ( accessToken !== undefined && accessToken !== null && accessToken !== '' ) {
// Try to contact the server to see if it's still viable
} else {
// Go to the login page because you're certainly not logged
localStorage.setItem( 'accessToken', "" );
this.setState({
accessToken: "",
isLogged: false,
});
}
}
render() {
let redirect;
if ( this.state.isLogged === false ) {
redirect = <Redirect to={{ pathname: '/login' }} />;
}
let pages;
if ( this.state.isLogged === undefined ) {
pages = <Loading/>;
} else {
pages = <div>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</div>;
}
return(
<Router>
<div className="page-wrapper">
<Menu />
<div className="site-content">
{pages}
{redirect}
</div>
<Footer />
</div>
</Router>
);
}
}
Menu.js
import React, { Component } from 'react';
import logo from './../assets/img/logo.png';
export default class Menu extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
menuState: 0,
}
}
toggleMenu() {
this.setState({
menuState: 1 - this.state.menuState
});
}
changeLanguage(language) {
alert('change language');
}
render() {
return(
<header>
<div className="menu-bar">
<div className="top-bar">
<div className="icon open" onClick={this.toggleMenu.bind( this )}></div>
<div className="logo-wrapper">
<img src={logo} alt="logo" />
</div>
<div className="language-selection-wrapper"></div>
</div>
<div className={this.state.menuState === 1 ? "menu-body opened" : "menu-body closed"}>
<div className="menu-sidebar">
<div className="sidebar-content">
<div className="sidebar-top-bar">
<div className="icon close" onClick={this.toggleMenu.bind( this, 1 )}></div>
<div className="logo-wrapper">
<img src={logo} alt="logo" />
</div>
</div>
<div className="language-selection-wrapper">
<div className={this.state.language === 'it' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'it')}>IT</div>
<div className={this.state.language === 'en' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'en')}>EN</div>
<div className={this.state.language === 'de' ? "language current" : "language"} onClick={this.changeLanguage.bind(this, 'de')}>DE</div>
</div>
</div>
</div>
</div>
</div>
</header>
);
}
}
And at the end Login.js
import React, { Component } from 'react';
import Globals from './../globals/globals.js';
import Loading from './../components/Loading.js';
import 'font-awesome/css/font-awesome.min.css';
export default class Login extends Component {
constructor(props) {
super(props);
this.state = {
language: "en",
loading: false
}
}
componentDidMount(){
document.title = "Login"
}
doLogin() {
alert('Fai il login');
this.setState({
loading: true
});
}
render() {
let loading;
if ( this.state.loading === true ) {
loading = <Loading/>;
}
return(
<div className="login-box">
<div className="welcome-message">
{Globals.messages.welcome[this.state.language]}
</div>
<div className="input-wrapper">
<input type="text" name="username" placeholder={Globals.placeholders.email[this.state.language]} />
</div>
<div className="input-wrapper">
<input type="password" name="password" placeholder={Globals.placeholders.password[this.state.language]} />
</div>
<div className="input-wrapper">
<button type="button" onClick={this.doLogin.bind(this)}><i className="fa fa-sign-in"></i><span>{Globals.placeholders.login[this.state.language]}</span></button>
</div>
{loading}
</div>
);
}
}
I'm also giving the globals.js file with translations
const Globals = {
baseUrl: "https://www.mywebsite.it/webservices/1.0/",
messages: {
welcome: {
it: "Benvenuto!",
en: "Welcome!",
de: "Willkommen!",
},
},
placeholders: {
email: {
it: "Email",
en: "Email",
de: "Email",
},
password: {
it: "Password",
en: "Password",
de: "Password",
},
login: {
it: "Login",
en: "Login",
de: "Login",
},
},
}
export default Globals;
you do not need Redux for internationalization.
Take a look at:
https://github.com/formatjs/react-intl
That's is the industry default for internationalization.