I have an application which has 3 pages .home ,shop,about.I want to add authentication to only page ie shop. When the user want to go to the shop page he has to login then only the user will go the shop page. I am maintaining a global state which has intital value isLogin:False. I extracted this value through mapStatetoProps in my App.js where all my Routes are there.For /shop path i am using the value as ternary condition. Initially the value (isLogin) is false it will render the Login page upon clicking shop link. But after proper authentication i am unable to redirect to the shop page
//App.js
import React ,{Component} from 'react';
import './App.css';
import Navigation from './Step1/Navbar'
import Home from './Step1/Home'
import Shop from './Step1/Shop'
import About from './Step1/About'
import Login from './LoginAuthentication/Loginform'
import {BrowserRouter as Router,Route} from 'react-router-dom'
import {connect} from 'react-redux'
const mapStateToProps=(state)=>{
console.log(state)
return{
isLogin:state.isLogin
}
}
class App extends Component {
render(){
return (
<Router>
<div className="App">
<Navigation/>
<Route path="/" exact component={Home}/>
<Route path="/about" component={About}/>
<Route path="/shop"
render={({isLogin}) =>(
isLogin ? <Shop/> : <Login/>
) }
/>
</div>
</Router>
);
}
}
export default connect(mapStateToProps,null)(App);
//Navigation
import React from 'react'
import {NavLink} from 'react-router-dom'
const Navbar=()=> {
return (
<div>
<nav className="navbar navbar-expand-sm bg-dark">
<ul className="navbar-nav">
<li className="nav-item"><NavLink to="/" >Home</NavLink> </li>
<li className="nav-item"><NavLink to="/shop">Shop </NavLink> </li>
<li className="nav-item"><NavLink to ="/About">About </NavLink> </li>
<li className="nav-item"><NavLink to ="/page">Page </NavLink> </li>
</ul>
</nav>
</div>
)
}
export default Navbar
// LoginForm.js
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {withRouter} from 'react-router-dom'
//import {Redirect} from 'react-router-dom'
import {action1} from '../Actions/action1'
const mapDispatchToProps=(dispatch)=>{
return{
LoginCheck:()=>dispatch(action1())
}
}
class Loginform extends Component {
state={
username:'',
password:'',
uname:'dharmendra',
pwd:'230498'
}
nameHandler=(event)=>{
if(event.target.name==='UserName'){
this.setState({username:event.target.value})
}
if(event.target.name==='Password'){
this.setState({password:event.target.value})
}
}
submitHandler=(event,state)=>{
event.preventDefault()
const uname=this.state.uname
const pwd=this.state.pwd
if(this.state.username===uname && this.state.password===pwd){
this.props.LoginCheck()
//return <Redirect to="/shop"/>
//this.props.history.push("/shop")
this.props.history.push("/page");
console.log('hi i am in shop page successful')
}
else{
alert("Enter proper Credentials")
}
}
render() {
return (
<div className="login">
<form onSubmit={this.submitHandler}>
<div className="form-group">
<h1>
<input
type="text"
placeholder="UserName"
value={this.state.username}
onChange={this.nameHandler}
className="form-control"
name="UserName"
/>
</h1>
</div>
<br></br>
<div className="form-group">
<h1>
<input
type="password"
placeholder="Password"
value={this.state.password}
onChange={this.nameHandler}
className="form-control"
name="Password"
/>
</h1>
</div>
<br></br>
<div className="form-group">
<button type="submit" className="btn btn-success" >Login</button>
</div>
</form>
</div>
)
}
}
export default withRouter(connect(null,mapDispatchToProps)(Loginform))
//reducer1.js
import {LOGINCHECK} from '../Constants/actiontypes'
const initialState={
isLogin:false
}
const reducer1=(state=initialState,action)=>{
//console.log(action.type)
//console.log(state)
if(action.type===LOGINCHECK){
return Object.assign({},state,{isLogin:true})
}
return state
}
export default reducer1
//action.js
import {LOGINCHECK} from '../Constants/actiontypes'
export const action1 =()=>{
return{
type:LOGINCHECK
}
}
Unable to redirect to the shop page even after proper authentication also
Change the route like this :
<Route path="/shop"
render={() =>(
this.props.isLogin ? <Shop/> : <Login/>
) }
/>
The props that are passed to the render prop in the Route components are route props, not the App component props (they don't contain isLogin)
https://reacttraining.com/react-router/web/api/Route/route-props
Related
I used to show my New arrival page from Home page when i select books. I Planned to show only a book that is selected in Home page book list. But its now showing in New arrival page right now. Please help me to get rid off.
import React from "react";
const BookDetails = (props) => {
console.log(props.book);
if (props.book === null) return <div></div>;
return (
<div>
<h3>{props.book.bookName}</h3>
</div>
);
};
export default BookDetails;
(This is another code i used my onclick fucntion)
import React from "react";
import Book from "../Representational/Book";
import { withRouter } from "react-router-dom";
const ComponentList = (props) => {
return props.books.map((item, index) => {
return (
<Book
bookName={item.bookName}
writer={item.writer}
publish={item.publish}
key={item.id}
selectedBookHandler={()=>props.selectedBookHandler(Book)}
/>
);
});
};
export default withRouter(ComponentList);
(Below are codes as main component)
import { Component } from "react";
import ComponentList from "./Lists/ComponentList";
import BookList from "../Assets/BookList";
import NewBook from "./Representational/NewBook";
import About from './Representational/About';
import {Route, NavLink} from 'react-router-dom';
import BookDetails from "./Representational/BookDetails";
class MainComponent extends Component {
constructor(props){
super(props)
this.state = {
books: BookList,
selectedBook: null
}
}
selectedBookHandler = books=>{
this.setState({
selectedBook: books
})
}
render() {
const newCopy = (
<ComponentList
books={this.state.books}
selectedBookHandler={this.selectedBookHandler}
/>
);
return (
<div className="book-project">
<nav className="nav-bar">
<ul>
<li>
<NavLink to="/" exact>Home</NavLink></li>
<li><NavLink to="/new">New Arrival</NavLink></li>
<li><NavLink to="/about-us">About Us</NavLink></li>
</ul>
</nav>
<div>
<Route path="/" exact render={()=> newCopy} />
<Route path="/new" exact component={NewBook}/>
<Route path="/about-us" exact component= {About}/>
<BookDetails book={this.state.selectedBook}/>
</div>
<div className="head">
<h1 className="appHeading head">New Book List</h1>
</div>
<div className="btn">
<button onClick={this.toggleBook}>Toggle</button>
<input type="text" onChange={this.changeInputState} />
</div>
</div>
);
}
}
export default MainComponent;
Please Help me.
Have a pretty basic app through ReactJS but having trouble with routing to a new page and can't figure out why. When I click on the box that should route me to the Quiz page, the contents on that page populate (just saying "hello") but everything else on the page stays the same. I thought it had to do with the exact path but even still, everything remains the same and doesnt just show what's within my Quiz Component. Any thoughts? Appreciate all the help!
APP.JS
import React, { Component } from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import Home from "./Components/Home/Home"
import Header from "./Components/Header/Header"
import Modal from "./Components/Modal/Modal"
import Quiz from "./Components/Quiz/Quiz"
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
questions: this.props.questions,
show: false,
};
}
// Function that opens/closes Modal
showModal = () => {
this.setState({ show: !this.state.show })
}
render() {
return (
<div>
<header>
<Header />
{/* Input button for Modal */}
<input
className='open-modal-btn'
type='button'
onClick={this.showModal}
value=' Show Modal'
/>
<Modal show={this.state.show} onClose={this.showModal}>
This message is from Modal
</Modal>
</header>
<Home />
<div>
<Switch>
<Route
exact
path='/quiz'
render={() => {
return (
<Quiz />
);
}}
/>
</Switch>
</div>
</div>
);
}
}
export default App;
Home.JS
import React, { Component } from 'react';
import './Home.css';
import { Link } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
this.state = { username: '' };
}
// Updates the name of the User input Box
handleChange = (event) => {
this.setState({ username: event.target.value });
};
render() {
return (
<main>
<div>
<form>
<label htmlFor='Username'> Username: </label>
<input
type='text'
name='username'
value={this.state.username}
onChange={this.handleChange}
/>
</form>
<div className='Allboxes'>
<div className='boxOne'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Boston, MA <br />
<b> Interests: </b>Long walks on the beach, Golden Girls <br />
</div>
<div className='boxTwo'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Dallas, TX <br />
<b> Interests: </b>Opera, Dank Memes <br />
</div>
<div className='boxThree'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Long Beach, CA <br />
<b> Interests: </b>Shredding the Gnar, playing with yoyo's <br />
</div>
<Link to='/quiz'>
<div className='boxFour'>
<b> Name: </b> {this.state.username} <br />
<b> From: </b> Chicago, IL <br />
<b> Interests: </b>Pokemon, More Pokemon, Daisies <br />
</div>
</Link>
</div>
</div>
</main>
);
}
}
export default Home;
QUIZ.JS
import React, { Component } from 'react';
class Quiz extends Component {
render() {
return (
<div>
Hello
</div>
);
}
}
export default Quiz;
HEADER.JS
import React, { Component} from 'react';
import './Header.css';
import { Link } from 'react-router-dom';
class Header extends Component {
render() {
return (
<div>
<h1> Who Wants to be a Tandem Millionaire </h1>
<Link to='/'> Home </Link>
</div>
);
}
}
export default Header;
MODAL.JS
import React, { Component } from 'react';
import './Modal.css';
export default class Modal extends React.Component {
// Function that closes the Modal Button
onClose = (e) => {
this.props.onClose && this.props.onClose(e);
};
render() {
if (!this.props.show) {
return null;
}
return (
<div className='backdropStyle'>
<div className='modalStyle'>
{this.props.children}
<div className='footerStyle'>
<button
className='close-modal-btn'
onClick={(e) => {
this.onClose(e);
}}>
Close
</button>
</div>
</div>
</div>
);
}
}
I think the bug here could be that you did not wrap your App.js with Browser Router
Code below is a simple structuring of react-router
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'
import React from 'react'
const App = ()=>{
<Router>
<Switch>
<Route path="/another-route" exact={true}>
<AnotherComponent />
</Route>
<Route path="/" exact={true}>
<HomeComponent />
</Route>
</Switch>
</Router>
}
So following such a structure will get your React Routing well and even cleaner having App.js structured in such format,
You can also refer to the documentation if what I wrote does not make any sense
https://reactrouter.com/web/guides/quick-start
In this function:
import React, { useEffect } from 'react';
import { BrowserRouter, Route, Link } from 'react-router-dom'
import HomeScreen from './Screens/HomeScreen'
import './App.css';
import currentStrings from './utils/currentlang'
function App() {
const [currentlang, setCurrentStrings] = React.useState(currentStrings)
return (
<BrowserRouter>
<div className="grid-container">
<header className="header">
<div className="brand">
<Link to="/" >
</Link>
</div>
<div className="header-side">
{currentlang.getCurrent.subtitle}
</div>
<div className="header-right">
<button onClick={() => setCurrentStrings(currentlang.switchLang())}> {currentlang.getCurrent.traduction} </button>
</div>
<div>
</div>
</header>
<main className="main">
<div className="content">
<Route path="/" exact={true} component={HomeScreen} />
</div>
</main>
<footer className="footer">
© 2020
</footer>
</div>
</BrowserRouter>
);
}
export default App;
I use a button (<button onClick={() => setCurrentStrings(currentlang.switchLang())}> ) to change one of the properties of the object currentStrings (or currentLang used for the useState hook)
However it seems my function does not rerender, i can confirm this since my logs do tell the object does change its properties when the button is clicked, but the screen does not show it.
import {strings as frstrings} from '../res/lang/fr/strings'
import {strings as engstrings} from '../res/lang/eng/strings'
class CurentLang {
constructor(){
this.current = engstrings;
}
switchLang() {
if(this.current === frstrings){
this.current = engstrings;
console.log("engstrings");
} else{
this.current = frstrings;
console.log("frstrings");
}
return new this.CurentLang;
}
get getCurrent(){
return this.current;
}
}
var currentStrings = new CurentLang()
export default currentStrings;
Can someone please help me? I'm trying to pass data through context from one component to another (from Search.js to Container.js). However, I'm getting a type error. I searched many questions in Web, but haven't found an answer. Sorry, if it's childish problem, I'm new.
Search.js:
import React, { Component } from 'react'
import { StyledFormSearchBar } from '../styles'
import { data } from '../data'
const SearchContext = React.createContext()
export default class Search extends Component {
constructor() {
super()
this.state = {
value: '',
results: [],
areResultsVisible: false
}
this.handleSearch = this.handleSearch.bind(this)
}
handleSearch(e) {
this.setState = {
value: e.target.value,
results: data.filter(item => {
return item.title.toLowerCase().includes(e.target.value.toLowerCase())
}),
areResultsVisible: true
}
}
render() {
return (
<StyledFormSearchBar>
<input type="search" name="search" className="border border-dark rounded" onSubmit={this.handleSearch}/>
<button type="submit" value="submit" className="bg-warning border-0 text-danger rounded-right position-relative">
<i className="fas fa-search"></i>
</button>
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
</StyledFormSearchBar>
)
}
}
const SearchContextConsumer = SearchContext.Consumer
export { SearchContextConsumer }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Container.js:
import React from 'react'
import { Route, Switch } from "react-router-dom"
import { StyledDivGridContainer } from './styles'
import { SearchContextConsumer } from './header/Search'
import Carousel from './container/Carousel'
import MobilePhonesDiscount from './container/products/carousel/MobilePhonesDiscount'
import LaptopsDiscount from './container/products/carousel/LaptopsDiscount'
import TabletsDiscount from './container/products/carousel/TabletsDiscount'
import Products from './container/Products'
import SearchResults from './container/SearchResults'
import MobilePhones from './container/products/MobilePhones'
import Laptops from './container/products/Laptops'
import Tablets from './container/products/Tablets'
import ProductPage from './container/ProductPage'
import About from './container/About'
import ContactUs from './container/ContactUs'
export default function Container() {
return (
<StyledDivGridContainer>
<div className="no-gutters justify-content-between">
<SearchContextConsumer>
{
value => {
return (
!value.areResultsVisible
? <Switch>
<Route exact path="/" component={Carousel}/>
<Route exact path="/" component={Products}/>
</Switch>
: <Route exact path="/" component={SearchResults}/>
)
}
}
</SearchContextConsumer>
<Route path="/mobile_phones_discount" component={MobilePhonesDiscount}/>
<Route path="/laptops_discount" component={LaptopsDiscount}/>
<Route path="/tablets_discount" component={TabletsDiscount}/>
<Route path="/mobile_phones" component={MobilePhones}/>
<Route path="/laptops" component={Laptops}/>
<Route path="/tablets" component={Tablets}/>
<Route path="/product_page" component={ProductPage}/>
<Route path="/about" component={About}/>
<Route path="/contact_us" component={ContactUs}/>
</div>
</StyledDivGridContainer>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Search.js is in Header.js:
import React, { Component } from 'react'
import { StyledHeader,
StyledSpanAccount } from './styles'
import { Link } from "react-router-dom"
import Catalogue from "./header/Catalogue"
import Search from "./header/Search"
export default class Header extends Component {
render() {
return (
<StyledHeader className="d-flex w-100 bg-light shadow justify-content-center">
<div className="d-flex flex-wrap justify-content-around align-items-center">
<div className="my-1 mr-3">
<Link to="/" className="logo">
<img src={require('../img/logo.webp')} alt="logo" className="img-tumbnail"/>
</Link>
</div>
<Catalogue/>
<Search/>
<div className="d-flex my-3">
<i className="fas fa-shopping-cart"></i>
<i className="fas fa-user-alt ml-3"></i>
<a href="#" className="d-flex flex-nowrap">
<StyledSpanAccount className="ml-2">Log in</StyledSpanAccount>
</a>
<a href="#" className="d-flex flex-nowrap">
<StyledSpanAccount className="ml-2">Sing up</StyledSpanAccount>
</a>
</div>
</div>
</StyledHeader>
)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Container.js is in App.js near Header.js:
import React from 'react';
import { Route } from "react-router-dom";
import { StyledDivWrapper } from './components/styles';
import Header from './components/Header';
import Container from './components/Container';
import Footer from './components/Footer';
export default function App() {
return (
<StyledDivWrapper className="d-flex flex-column">
<Route path="/" component={Header}/>
<Route path="/" component={Container}/>
<Route path="/" component={Footer}/>
</StyledDivWrapper>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Error screenshot
My folder tree
The problem is that your Container component is not within your SearchContext.Provider. To make sure your code works correctly you must have your SearchContext Provider directly inside you App Component so that it is a common parent of both Search and Container component
Firstly, create a context in a different file
// SearchContext.js
export const SearchContext = React.createContext();
const SearchContextConsumer = SearchContext.Consumer
export { SearchContextConsumer }
Secondly, create a component which acts as a provider
// SearchProvider.js
class SearchProvider extends React.Component {
constructor() {
super()
this.state = {
value: '',
results: [],
areResultsVisible: false
}
this.handleSearch = this.handleSearch.bind(this)
}
handleSearch(e) {
this.setState = {
value: e.target.value,
results: data.filter(item => {
return item.title.toLowerCase().includes(e.target.value.toLowerCase())
}),
areResultsVisible: true
}
}
render() {
return (
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
)
}
}
Now you Search Component would simply be
// Search.js
export default class Search extends Component {
render() {
return (
<SearchContext.Consumer>
{({handleSearch}) => (
<StyledFormSearchBar>
<input type="search" name="search" className="border border-dark rounded" onSubmit={handleSearch}/>
<button type="submit" value="submit" className="bg-warning border-0 text-danger rounded-right position-relative">
<i className="fas fa-search"></i>
</button>
</StyledFormSearchBar>
)}
</SearchContext.Consumer>
)
}
}
Also no you can use your SearchProvider in App.js like
export default function App() {
return (
<SearchProvider>
<StyledDivWrapper className="d-flex flex-column">
<Route path="/" component={Header}/>
<Route path="/" component={Container}/>
<Route path="/" component={Footer}/>
</StyledDivWrapper>
</SearchProvider>
);
}
You first need to wrap your top level component with the context provider (Search), because the point of the context api is to pass the data top-down without having to explicitly pass it through every level, otherwise the context consumer won't have any context to consume in first place:
<Search>
<App />
</Search>
Also, you need to use the prop value to pass the context from the provider, and not any prop (like searchValue in your code):
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
Import createContext like
import { React, createContext } from 'react';
export const MyContext = createContext();
this helped me.
I am new to React. I would like to redirect to another page (another component) called MainModule from the login form after clicking the submit button.
This is my Login Form=>
import React, {Component} from "react";
import { withRouter} from 'react-router-dom';
import {Button,FormGroup,FormControl,FormLabel,Form} from "react-bootstrap";
class Login extends Component {
constructor(props){
super(props);
this.state={
email:"",
password:""
};
}
handelChange = event =>{
this.setState({
[event.target.id]:event.target.value
},()=>{
});
}
handelSubmit = event => {
event.preventDefault();
this.props.history.push('/MainModule');
}
render()
{
return (
<div className="Login">
<Form onSubmit={this.handelSubmit}>
<FormGroup controlId="email">
<FormLabel>Email</FormLabel>
<FormControl autoFocus type="email" value={this.state.email} onChange={this.handelChange}/>
</FormGroup>
<FormGroup controlId="password">
<FormLabel>Password</FormLabel>
<FormControl type="password" value={this.state.password} onChange={this.handelChange}/>
</FormGroup>
<Button type="submit">Login</Button>
</Form>
</div>
)
}
}
export default withRouter(Login);
but the problem is after I clicking the submit button, url change to MainModule but MainMoudle form is not shown and just showing the current login form.I think this needs to defind the route for MainModule and I don't know how to do that. Please help.
Update
My MainModules =>
import React from 'react';
import { Route, Link,Switch,BrowserRouter } from "react-router-dom";
import allowance from './components/master/allowance';
class MainModule extends React.Component {
// constructor(props){
// super(props)
// }
render(){
return(
<div className="mainform">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<Link className="navbar-brand" to="/MainModule">TMS</Link>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavAltMarkup">
<div className="navbar-nav">
<Link className="nav-item nav-link" to={'/allowance'}>Allowance</Link>
</div>
</div>
</nav>
<div id="maincontent">
<Route path='/allowance' component={allowance} />
</div>
</div>
)
}
}
export default MainModule;
You are correct, you do have to define a route for your MainModule component.
In your App.js file, which is where I'm assuming you have set up your Routes:
import React from "react"
import { BrowserRouter, Route } from "react-router-dom"
import Login from "/yourcomponentfolder/Login"
import MainModule from "/yourcomponentfolder/MainModule"
const App = () => {
return(
<BrowserRouter>
<div>
//Using exact tells react-router that you will only render this component if the URL matches exactly with the path definition.
<Route path="/" component={Login} exact/>
<Route path="/MainModule" component={MainModule}/>
</div>
</BrowserRouter>
)
}
It's pretty cut and dry, you use the Route component, give it a path, and a component to render.