I'm just beginner for React. Now, I'm trying to protect route and there's no error and nothing on the console that could explain what's wrong why it doesn't show the component as it should be.
Here are my codes.
//App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Login from './Login';
import Dashboard from './Dashboard';
import { ProtectedRoute } from './ProtectedRoute';
import Logout from './Logout';
export default class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Login} />
<ProtectedRoute path="/dashboard" component={Dashboard} />
<Route path="/logout" component={Logout} />
<Route path="*" component={() => "404 NOT FOUND"} />
</Switch>
</BrowserRouter>
)
}
}
//ProtectedRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import auth from './auth';
export const ProtectedRoute = ({ component: Component, ...rest }) => {
return(
<Route
{...rest}
render = {props => {
auth.isAuthenticated().then(resp =>
resp === true ? (<Component {...props} {...rest} />) : (
<Redirect to={
{
pathname: "/",
state: {
from: props.location
}
}
} />
)
).catch(error => {
alert(error);
});
}}
/>
);
};
...
//auth.js
import axios from 'axios';
axios.defaults.withCredentials = true;
class Auth {
constructor(){
this.host = 'http://' + window.location.hostname + ':5000';
}
isAuthenticated(){
return new Promise((resolve, reject) => {
axios.get(`${this.host}/getsignin`).then(resp => {
console.log('resp.data from isAuthenticated() : '+resp.data);
resolve(resp.data)
}).catch(error => {
reject(error);
});
});
}
login(username, password){
return new Promise((resolve, reject) => {
axios.post(`${this.host}/signin`, {
user: username,
password: password
}).then(resp => {
let rs = JSON.stringify(resp.data);
if(rs === "1"){
resolve(true);
}else{
resolve(false);
}
}).catch(error => {
reject(error);
});
});
}
}
export default new Auth();
...
//Login.js
import React, { Component } from 'react';
import $ from 'jquery';
import { WaveLoading } from 'react-loadingg';
import auth from './apis/auth';
import { Redirect } from 'react-router';
export default class Login extends Component {
constructor(props){
super(props);
this.state = {
redirect: false,
loading: true
}
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(){
auth.login($('#txtUser').val(), $('#txtPass').val())
.then(resp => {
this.setState({
redirect : resp
});
}).catch(error => {
alert(error);
});
}
showLogin(){
return(
<div className="hold-transition login-page">
<div className="login-box">
<div className="login-logo">
<b>KVC Computer</b>
</div>
<div className="card">
<div className="card-body login-card-body">
<p className="login-box-msg">Sign in</p>
<div className="input-group mb-3">
<input type="text" className="form-control" placeholder="Username" name="txtUser" id="txtUser" />
<div className="input-group-append">
<div className="input-group-text">
<span className="fas fa-user" />
</div>
</div>
</div>
<div className="input-group mb-3">
<input type="password" className="form-control" placeholder="Password" name="txtPass" id="txtPass" />
<div className="input-group-append">
<div className="input-group-text">
<span className="fas fa-lock" />
</div>
</div>
</div>
<div className="row">
<div className="col-8">
<div className="icheck-primary">
<input type="checkbox" id="chkRem" name="chkRem" />
<label htmlFor="remember">
Remember Me
</label>
</div>
</div>
<div className="col-4">
<button className="btn btn-primary btn-block" name="btnSignin" id="btnSignin" onClick={this.onSubmit}>Sign In</button>
</div>
</div>
<div className="social-auth-links text-center mb-3">
<p>- OR -</p>
</div>
<p className="mb-1">
forgot your password
</p>
</div>
</div>
</div>
</div>
)
}
componentDidMount(){
this.setState({ loading : false });
auth.isAuthenticated().then(res => {
this.setState({ redirect : res });
console.log('isAuthenticat : '+res);
})
}
render() {
if(this.state.redirect){
return <Redirect to="/dashboard" />;
}
return (
this.state.loading ? <WaveLoading /> : this.showLogin()
)
}
}
Login.js -> If user already login then redirect to dashboard
//Dashboard.js
import React, { Component } from 'react';
export default class Dashboard extends Component {
constructor(props){
super(props);
console.log('constructor');
}
componentDidMount(){
console.log('componentDidMount');
}
onRender = () => {
return (
<div>
<h1>This is dashboard!!</h1>
</div>
);
}
render() {
console.log('render');
return (
this.onRender()
)
}
}
After user has logged in Auth.isAuthenticated() return true and ProtectedRoute should return Component to App (Dashboard). It shows nothing on the browser but the url is http://xxx.xxx.xxx.xxx/dashboard
I have no idea why is that happend and how to solve this. Should I change some code?
I'm stuck on this for days.
Thanks
Related
Coding a project using React. It's been 3 days I've looking for a solution. I had been learning coding and trying to integrate stripe payment option on my web-app. However, unable to get the proper result. Searched a lot, found no solution.
Code is below :
App.js
import { Elements } from '#stripe/react-stripe-js';
import { loadStripe } from '#stripe/stripe-js';
import { useEffect } from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import './App.css';
import Checkout from './Checkout';
import { auth } from './firebase';
import Header from './Header';
import Home from './Home';
import Login from './Login';
import Payment from './Payment';
import { useStateValue } from './StateProvider';
const promise = loadStripe("pk_test_51KtYdQSJwVy1hdNxUPD5HK8KcKbLDVSic6q6jfdPxuSLYiCjuwzBfE8Eo5u0zVclLgPP33InVTjAyM4rZP3ouWB9009AL3lsZ6");
function App() {
const [{ }, dispatch] = useStateValue();
useEffect(() => {
auth.onAuthStateChanged(authUser => {
console.log("THE USER IS >>>>> ", authUser);
if (authUser) {
dispatch({
type: "SET_USER",
user: authUser
});
}
else {
dispatch({
type: "SET_USER",
user: null
})
}
})
}, []);
return (
<BrowserRouter>
<div className="App">
<Header />
{console.log("load stripe>>>>>>>>",promise)}
<Routes>
<Route path="/payment" element={
<Elements stripe={promise}>
<Payment />
</Elements>
} />
<Route path="/login" element={<Login />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
Component in which using Stripe and CardElement (Payment.js) :
import { CardElement, useElements, useStripe } from "#stripe/react-stripe-js";
import React, { useState } from "react";
import CurrencyFormat from "react-currency-format";
import { Link } from "react-router-dom";
import CheckoutProduct from "./CheckoutProduct";
import "./Payment.css";
import { getBasketTotal } from "./reducer";
import { useStateValue } from "./StateProvider";
function Payment() {
const [{ basket, user }, dispatch] = useStateValue();
const stripe = useStripe();
const elements = useElements();
const [error,setError]=useState(null);
const [disabled,setDisabled]=useState(true);
const [succeeded,setSucceeded]=useState(false);
const [processing,setProcessing]=useState("");
const handleSubmit = event => {
//do all the stripe stuff
event.preventDefault();
}
const handleChange = event =>{
// Listen for changes in the CardElement
// and display any errors as the customer types card details
setDisabled(event.empty);
setError(event.error ? event.error.message : "");
}
return (
<div className="payment">
<div className="payment__container">
<h1>
Checkout ({<Link to="/checkout">{basket?.length} items</Link>})
</h1>
{/* Payment section - delivery address */}
<div className="payment__section">
<div className="payment__title">
<h3>Delivery Address</h3>
</div>
<div className="payment__address">
<p>{user?.email}</p>
<p>786 Chaurangi Marg</p>
<p>Delhi, India</p>
</div>
</div>
{/* Payment section - Review items */}
<div className="payment__section">
<div className="payment__title">
<h3>Review Items and Delivery</h3>
</div>
<div className="payment__items">
{basket.map(item =>
<CheckoutProduct
id={item.id}
title={item.title}
price={item.price}
rating={item.raing} />
)}
</div>
</div>
{/* Payment section - payment method */}
<div className="payment__section">
<div className="payment__title">
<h3>Payment Method</h3>
</div>
<div className="payment__details">
<form onSubmit={handleSubmit}>
{/*<CardElement />*/}
<div className="card__element">
<CardElement />
</div>
<div className="payment__priceContainer">
<CurrencyFormat
renderText={(value)=>(
<>
<h3>Order Total: {value}</h3>
</>
)}
decimalScale={2}
value={getBasketTotal(basket)}
displayType={"text"}
thousandSeparator={true}
prefix={"₹"}
/>
<button disabled={processing || disabled || succeeded}>
<span>{processing ? <p>Processing</p> : "Buy Now"}</span>
</button>
</div>
{error && <div>{error}</div> }
</form>
</div>
</div>
</div>
</div>
)
}
export default Payment;
I am not able to update my comment on the page.
After submiting it is showing comment object in the console log but not on the page Console log image
here is my comment.js
import {COMMENTS} from '../shared/comments';
import * as ActionType from './ActionTypes';
export const Comments=(state=COMMENTS ,action) => {
switch(action.type){
case ActionType.ADD_COMMENT:
var comment = action.payload;
comment.id = state.length;
comment.date = new Date().toISOString();
console.log("Comment: ", comment);
return state.concat(comment);
default:
return state;
};
}
here in my store
import {createStore, combineReducers} from 'redux';
import {Dishes} from './dishes';
import {Comments} from './comments';
import {Leaders} from './leaders';
import {Promotions} from './promotions';
export const ConfigureStore=() =>{
const store=createStore(
combineReducers({
dishes:Dishes,
comments:Comments,
leaders:Leaders,
promotions:Promotions
})
);
return store;
};
here is my action creator
import * as ActionTypes from './ActionTypes';
export const addComment=(dishID,rating,author,comment) => ({
type:ActionTypes.ADD_COMMENT,
payload:{
dishID:dishID,
rating:rating,
author:author,
comment:comment,
}
});
here is my App.js
import React from 'react';
import Main from './components/MainComponent';
import './App.css';
import {BrowserRouter} from 'react-router-dom';
import {Provider} from 'react-redux';
import {ConfigureStore} from './redux/configureStore';
const store=ConfigureStore();
class App extends React.Component {
render()
{
return (
<Provider store={store}>
<BrowserRouter>
<div>
<Main/>
</div>
</BrowserRouter>
</Provider>
);
}
}
export default App;
here is my MainComponent.js
import React from 'react';
import Menu from './MenuComponent';
import DishDetail from './DishdetailComponent';
import Home from './HomeComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import Contact from './ContactComponent';
import About from './AboutComponent';
import {Switch , Route , Redirect,withRouter } from 'react-router-dom';
import {connect} from 'react-redux';
import {addComment} from '../redux/ActionCreators'
const mapStateToProps=state =>{
return{
dishes:state.dishes,
leaders:state.leaders,
comments:state.comments,
promotions:state.promotions
}
};
const mapDispatchToProps = dispatch => ({
addComment:(dishId,rating,author,comment) => dispatch(addComment(dishId,rating,author,comment))
});
class Main extends React.Component {
render()
{
const HomePage=() => {
return(<Home dish={this.props.dishes.filter((dish) => dish.featured)[0]}
leader={this.props.leaders.filter((leader) => leader.featured)[0]}
promotion={this.props.promotions.filter((promo) => promo.featured)[0]} />);
}
const DishWithId=({match}) => {
return(
<DishDetail dish={this.props.dishes.filter((dish) => dish.id === parseInt(match.params.dishId,10))[0]}
comments={this.props.comments.filter(comment => comment.dishId === parseInt(match.params.dishId,10))}
addComment={this.props.addComment} />
);
};
return (
<div>
<Header/>
<Switch>
<Route path="/home" component={HomePage}/>
<Route exact path="/aboutus" component={() => <About leaders={this.props.leaders}/>}/>
<Route exact path="/menu" component={() => <Menu dishes={this.props.dishes}/>} />
<Route path="/menu/:dishId" component={DishWithId} />
<Route exact path="/contactus" component={() => <Contact/>}/>
<Redirect to="/home"/>
</Switch>
<Footer/>
</div>
);
}
}
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Main));
here is my dishdetail.js component
import React from 'react';
import '../App.css';
import { Card, CardImg, CardBody, CardTitle, CardText ,Breadcrumb ,BreadcrumbItem ,Button, Modal, ModalHeader, ModalBody, Label,Row} from 'reactstrap';
import { LocalForm, Control,Errors } from 'react-redux-form';
import {Link} from 'react-router-dom';
const maxLength=(len) => (val) => !(val) || (val.length <= len);
const minLength=(len) => (val) => (val) && (val.length >= len);
class CommentForm extends React.Component
{
constructor(props)
{
super(props);
this.state={
isModalOpen:false
};
this.toggleModal=this.toggleModal.bind(this);
this.handelSubmit=this.handelSubmit.bind(this);
}
toggleModal()
{
this.setState({
isModalOpen: !this.state.isModalOpen
});
}
handelSubmit(values)
{
this.props.addComment(this.props.dishId,values.rating,values.author,values.comment);
this.toggleModal();
}
render(){
return(
<React.Fragment>
<Button outline onClick={this.toggleModal}><span className="fa fa-pencil"></span>{' '}Submit Comment</Button>
{/*--Modal For Comment--*/}
<Modal id="commentModal" isOpen={this.state.isModalOpen} toggle={this.toggleModal}>
<ModalHeader toggle={this.toggleModal}>Submit Comment</ModalHeader>
<ModalBody>
<LocalForm onSubmit={(values) => this.handelSubmit(values)} >
<Row className="form-row mt-2">
<Label htmlFor="rating">Rating</Label>
<Control.select model=".rating"
id="rating"
name="rating"
className="form-control"
>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Control.select>
</Row>
<Row className="form-row mt-2">
<Label htmlFor="author">Your Name</Label>
<Control.text model=".author"
id="author"
name="author"
className="form-control"
placeholder="Your Name"
validators={{
minLength:minLength(3),
maxLength:maxLength(15)
}}
/>
<Errors
className="text-danger"
model=".author"
show="touched"
messages={{
minLength:'Must be greater than 2 characters',
maxLength:'Must be 15 characters or less'
}}/>
</Row>
<Row className="form-row mt-2">
<Label htmlFor="comment">Comment</Label>
<Control.textarea model=".comment"
rows="6"
id="comment"
name="comment"
className="form-control"
/>
</Row>
<Row className="form-row mt-2">
<Button type="submit" color="primary" >Submit</Button>
</Row>
</LocalForm>
</ModalBody>
</Modal>
</React.Fragment>
);
}
}
function RenderDish({dish})
{
return(
<div className="col-12 col-md-5 m-1">
<Card>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle><strong>{dish.name}</strong></CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
</div>
);
}
function RenderComments({comments,dishId,addComment})
{
if(comments!=null)
{
return(
<div className="col-12 col-md-5 m-1">
<h4>comments</h4>
<ul className="list-unstyled">
{comments.map(comment => {
return(
<li key={comment.id}>
<p>{comment.comment}</p>
<p>--{comment.author} ,{new Intl.DateTimeFormat('en-US',{year:'numeric',month:'short',day:'2-digit'}).format(new Date(Date.parse(comment.date)))}</p>
</li>
);
})}
</ul>
<CommentForm dishId={dishId} addComment={addComment}/>
</div>
);
}
else{
return <div></div>
}
}
function DishDetail(props)
{
if(props.dish!=null)
{
return(
<div className="container">
<div className="row">
<Breadcrumb >
<BreadcrumbItem><Link to="/home">Home</Link></BreadcrumbItem>
<BreadcrumbItem><Link to="/menu">Menu</Link></BreadcrumbItem>
<BreadcrumbItem>{props.dish.name}</BreadcrumbItem>
</Breadcrumb>
<div className="col-12">
<h3>{props.dish.name}</h3>
<hr/>
</div>
</div>
<div className="row">
<RenderDish dish={props.dish}/>
<RenderComments comments={props.comments} dishId={props.dish.id} addComment={props.addComment}/>
</div>
</div>
);
}
else
{
return(
<div></div>
);
}
}
export default DishDetail;
please help !!
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.
I use Laravel as backend and ReactJS as frontend. In ReactJS, create Routes.
In Laravel, create Api. When I parse the Parameter from ReactJS to Laravel, First time okay. After I reload these page, show Json Only
I tried Parameter Route like this "/:id" and work. But for multiple Objects it did not solve. It work for only one Object.
App.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch, browserHistory,IndexRoute } from 'react-router-dom'
import NewApp from './NewApp'
import AppList from './AppList'
import NAVBAR from './NAVBAR'
import Container from './Container'
import MainNavigation from './MainNavigation'
import AppSettingList from './AppSettingList'
import UpdateApp from './UpdateApp'
import {withRouter} from 'react-router';
class App extends Component {
render () {
console.log(window.location.pathname);
return (
<BrowserRouter>
<div>
{/* <Header /> */}
<NAVBAR />
<MainNavigation />
<Switch>
<Route exact path='/' component={withRouter(Container)} />
<Route exact path='/dashboard/' component={withRouter(Container)} />
<Route exact path='/app/' component={withRouter(AppList)} />
<Route exact path='/app/:id' component={withRouter(UpdateApp)} />
<Route exact path='/appsetting/' component={withRouter(AppSettingList)} />
<Route exact path='/app/create' component={withRouter(NewApp)} />
</Switch>
</div>
</BrowserRouter>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
UpdateApp.js
import axios from 'axios'
import React, { Component } from 'react'
import NiftySuccessModal from './alerts/NiftySuccessModal'
class UpdateApp extends Component {
constructor (props) {
super(props)
this.state = {
name: '',
description: '',
errors: [],
apps : [],
id : 0,
loading : false,
successModal : false
};
// binding
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.hasErrorFor = this.hasErrorFor.bind(this);
this.renderErrorFor = this.renderErrorFor.bind(this);
this.showSuccessModal = this.showSuccessModal.bind(this);
this.getApp = this.getApp.bind(this);
this.gotoApp = this.gotoApp.bind(this);
}
getApp(appId){
axios.get(`/app/${appId}`).then(response => { // return value
this.setState({
apps: response.data.apps,
name : response.data.apps.name,
id : response.data.apps.id
});
console.log(response.data.apps);
});
}
componentDidMount () {
const appId = this.props.match.params.id;
this.getApp(appId);
}
gotoApp(){
this.props.history.push('/app');
}
handleChange(e){
this.setState({
name: e.target.value
});
}
showSuccessModal(e){
this.setState({
successModal : true
});
setTimeout(() => {
this.setState({
successModal: false
})
}, 10000);
}
hasErrorFor (field) {
return !!this.state.errors[field]
}
renderErrorFor (field) {
if (this.hasErrorFor(field)) {
return (
<span className='invalid-feedback'>
<strong>{this.state.errors[field][0]}</strong>
</span>
)
}
}
handleSubmit(e){
e.preventDefault();
const params = {
id : this.state.id,
name: this.state.name
}
console.log('Update');
axios
.post('/app/update', params)
.then(response => {
console.log('Success');
})
.catch(error => {
console.log('Error');
this.setState({
errors: error.response.data.errors
});
})
}
render () {
return (
<div id="content-container">
<div id="page-head">
<div className={"pad-all text-center"}>
<h3>Welcome back to the Dashboard.</h3>
<p>Scroll down to see quick links and overviews of your Server, To do list, Order status or get some Help using Nifty.</p>
</div>
</div>
<div id="page-content">
<div className={"row"}>
<div className={"col-md-1"}></div>
<div className={"col-lg-9"}>
<NiftySuccessModal show={this.state.successModal} > Successfully Updated! </NiftySuccessModal>
<div className={"panel"}>
<div className={"panel-heading"}>
<h3 className={"panel-title"}>App </h3>
</div>
<form className={"panel-body form-horizontal form-padding"} onSubmit={this.handleSubmit}>
<div className={"form-group"}>
<label className={"col-md-3 control-label"} >App Name</label>
<div className={"col-md-9"}>
<input type="text"
name='name'
id='name'
onChange={this.handleChange}
value={this.state.name}
className={"form-control"}
maxLength="255"
placeholder="App Name..."
required className={"form-control"} placeholder="Text" />
<small className={"help-block"}>This is a help text</small>
</div>
</div>
<div className={"form-group demo-nifty-btn col-md-3"}>
<input type="submit" onClick={this.showSuccessModal} value="Update" className={"form-control btn btn-primary"} />
</div>
</form>
</div>
</div>
</div>
</div>{/* End <!--Page content--> */}
</div> // End <!--CONTENT CONTAINER-->
)
}
}
export default UpdateApp
![Before Reload]: (https://i.imgur.com/rWqFo9Y.png)
![After Reload]: (https://i.imgur.com/maR3x1S.png)
Now Solved! using difference route name and Query Strings with React Router. Page Reload also okay. Thanks.
that is not working
<Route path='/app' component={withRouter(AppList)} />
<Route path='/app/:id' component={withRouter(UpdateApp)} />
working with Query String
<Route path='/updateapp' component={withRouter(UpdateApp)} />
I'm trying to add information to a component but as soon as I click on the form button I get cannot read property map of undefined. Please help.
I've checked all the Db and routes, reducers etc. and they're all fine.
Here is component containing the form (The console.log returns "undefined")
import React from "react";
import { connect } from "react-redux";
import { addExercise } from "../actions/exercises";
class CreateExercise extends React.Component {
constructor(props) {
super(props);
this.state = {
newExercise: {},
};
}
handleSubmit(e) {
e.preventDefault();
e.target.reset();
this.props.dispatch(addExercise(this.state.newExercise));
}
updateDetails(e) {
let newExercise = this.state.newExercise;
newExercise[e.target.name] = e.target.value;
this.setState({ newExercise });
}
render() {
console.log("anything", this.props);
return (
<div className="form-container">
<form onSubmit={this.handleSubmit.bind(this)}>
<h2>Exercise Form</h2>
<div className="form">
<div>
<label>Name of Exercise:</label>
<input
name="exe_name"
type="text"
onChange={this.updateDetails.bind(this)}
/>
</div>
<div>
<label>Exercise Info:</label>
<input
name="exe_info"
type="text"
onChange={this.updateDetails.bind(this)}
/>
</div>
<div>
<label>Exercise Url:</label>
<input
name="exe_url"
type="text"
onChange={this.updateDetails.bind(this)}
/>
</div>
<div>
<label>Exercise Url2:</label>
<input
name="exe_url2"
type="text"
onChange={this.updateDetails.bind(this)}
/>
</div>
<div>
<label>Comment:</label>
<input
name="comment"
type="text"
onChange={this.updateDetails.bind(this)}
/>
</div>
</div>
<select name="plan_id" onChange={this.updateDetails.bind(this)}>
<option>Enter plan details</option>
{this.props.plans.map((plan, i) => {
return <option value={plan.plan_id}>{plan.sets}</option>;
})}
</select>
<input className="submit" type="submit" value="Submit" />
</form>;
</div>
);
}
}
const mapStateToProps = ({ plans }) => {
return { plans };
};
export default connect(mapStateToProps)(CreateExercise);
And here is the App component where it's being called.
import React from "react";
import { HashRouter as Router, Route } from "react-router-dom";
import { connect } from "react-redux";
import { getExercises } from "../actions/exercises";
import { getPlansRequest } from "../actions/plansActions";
import ExerciseList from "./ExerciseList";
import Header from "./Header";
import CreateExercise from "./CreateExercise";
import Single from "./Single";
import About from "./About";
import Home from "./Home";
import CreatePlan from "./CreatePlan";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showExerciseForm: false,
showPlanForm: false,
};
}
componentDidMount() {
this.props.dispatch(getPlansRequest());
this.props.dispatch(getExercises());
}
toggleForm(e) {
this.setState({ [e.target.name]: !this.state[e.target.name] });
}
render() {
return (
<Router>
<div className="app-container">
<div className="sidebar pure-u-1 pure-u-md-1-4">
<Header />
</div>
<Route
exact
path="/"
component={() => (
<button
name="showExerciseForm"
onClick={this.toggleForm.bind(this)}
>
{this.state.showExerciseForm ? "Cancel" : "Create Exercise"}
</button>
)}
/>
{this.state.showExerciseForm && (
<Route exact path="/" component={CreateExercise} />
)}
<Route
exact
path="/"
component={() => (
<button name="showPlanForm" onClick={this.toggleForm.bind(this)}>
{this.state.showPlanForm ? "Cancel" : "Create Plan"}
</button>
)}
/>
{this.state.showPlanForm && (
<Route exact path="/" component={CreatePlan} />
)}
<Route exact path="/exercises" component={ExerciseList} />
<Route
exact
path="/exercises/:id"
component={props => <Single {...props} />}
/>
<Route path="/about" component={About} />
<Route path="/" component={Home} />
</div>
</Router>
);
}
}
export default connect()(App);
You must send some props in the route to fetch them in component
In App component
{this.state.showExerciseForm && (<Route exact path="/" foobar="Something" component={CreateExercise} />)}
In CreateExercise fetch props by
this.props.foobar