I try to create a navbar which later will change after logging in based on user role, but after I tried it the navbar was successfully changed after login or logout, BUT if I should refresh the browser. so if i don't refresh the browser then the navbar won't change. how to solve it? here's the code of app.js
import React from 'react';
import './App.css';
import 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import NavbarAwal from './Component/NavbarAwal';
import jwt_decode from 'jwt-decode';
import 'react-bootstrap';
import NavbarPembeli from './Component/NavbarUser';
import NavbarPenjual from './Component/NavbarPenjual';
import { login, register } from './View/UserFunctions';
import Routes from './Router';
class App extends React.Component {
constructor() {
super();
this.state = {
Roles: "",
};
}
render() {
const token=localStorage.getItem('usertoken');
if(token===null){
return (
<div id="root">
<NavbarAwal/>
<Routes/>
</div>
)
}
const decoded = jwt_decode(token);
if (decoded.Roles === "Penjual") {
return (
<div id="root">
<NavbarPenjual/>
<Routes/>
</div>
)
} else if (decoded.Roles === "Pembeli") {
return (
<div id="root">
<NavbarPembeli/>
<Routes/>
</div>
)
} else {
return (
<div>
<NavbarAwal/>
<Routes/>
</div>
)
}
}
}
export default App;
Related
I have two buttons in my code, each trying a different way for redirecting, in one of them i'm trying to use <a>, and the other one I'm trying to use route, but none of them seem to work.
Here's my code:
Component DefineDestino.js:
import React, {useState} from "react"
import { Link, BrowserRouter, Routes, Route } from "react-router-dom"
import CheckOut from "../CheckOut"
export default function DefineDestino(props) {
const [initialValue, setValue] = useState(0)
const increment = () => {
return {
type:'counter/increment'
}
}
function estadosReducer(state, action) {
if (state === 'Rio de Janeiro' && action.type === 'counter/increment') {
setValue(initialValue + 1000)
}
}
return(
<div>
<h1>Valor: {initialValue}</h1>
<button onClick={() => estadosReducer(props.data, increment())}>Efetuar Compra</button>
</div>
)
}
App.js:
import Origem from './components/Origem';
import Destino from './components/Destino'
import './styles/App.css';
import React, {useState} from "react"
import EstadosOrigem from './components/Origem';
import EstadosDestino from './components/Destino';
import DefineDestino from './components/DefineDestino';
import { Link, BrowserRouter as Router, Routes, Route, Switch } from "react-router-dom";
import CheckOut from './CheckOut';
function App() {
return (
<Router>
<div className="App">
<div className="mainContent">
<h1>Escolha um destino.</h1>
< EstadosOrigem ></EstadosOrigem>
< EstadosDestino ></EstadosDestino>
<Routes>
<Route path="/CheckOut" component={CheckOut}></Route>
</Routes>
</div>
</div>
</Router>
);
}
export default App;
The page I'm trying to redirect to CheckOut.js:
function CheckOut() {
return (
<div className="CheckOut">
<div className="mainContent">
<h1>TESTE.</h1>
</div>
</div>
);
}
export default CheckOut;
I want to implement the navigation on menu bar which I am fetching from api. For e.g. on home page I have four menus like menu1 menu2 menu3 menu4 which displays always. On click on these menus i want to fetch products related to them.
I have read about nested routes in React js but unable to implement that.
Dynamic menu bar of categories:
import React from 'react';
import './style.css';
import {Link} from 'react-router-dom';
import Api from '../../Api';
class TopMenu extends React.Component {
state = {
categories : []
}
componentDidMount(){
Api.get(`categories`).then(
response => {
this.setState({categories: response.data});
});
};
render(){
return (
<div className="menu">
{this.state.categories.map(category => (
<Link to={"/category/" + category.name} key={category.id} className="menu-item"><span>{category.name}</span></Link>
))}
</div>
);
}
};
export default TopMenu;
My Routes file:
import React from 'react';
import {Switch, Route} from 'react-router-dom';
import CategoryProducts from './CategoryProducts';
import Home from './Home';
const Routes = () => {
return(
<Switch>
<Route path='/' exact component={Home} />
<Route path='/category/:name' component={CategoryProducts} />
</Switch>
);
};
export default Routes;
The click on Category will just change the browser url, not the page.
CategoryProducts.ja
import React from 'react';
import Products from './Products';
class CategoryProducts extends React.Component {
render(){
return (
<div className="content-wrapper">
<div className="menu-left">
<Products/>
</div>
</div>
);
}
}
export default CategoryProducts;
Products.js
import React,{useState, useEffect} from 'react';
import Api from './Api'
import Card from './components/Card';
class Products extends React.Component {
state = {
categories : []
}
componentDidMount(){
let categoryName = this.props.match ? this.props.match.params.name : 'Veg Pizza';
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
};
render(){
return (
<div>
<div className="ref">
<div className="menu-hr"></div>
<div className="menu-cat">
<div className="menu-catname ">BESTSELLERS</div>
</div>
</div>
<div className="card-container">
<div className="all-cards" data-label="Bestsellers">
<Card />
</div>
</div>
</div>
);
}
};
export default Products;
Your Products component is not mounting again and again, because this renders on all possible categories. Therefore In order to fetch data for different categories, you might have to use componentDidUpdate lifecycle method.
import React,{useState, useEffect} from 'react';
import Api from './Api'
import Card from './components/Card';
class Products extends React.Component {
state = {
categories : []
}
componentDidMount(){
let categoryName = this.props.match ? this.props.match.params.name : 'Veg Pizza';
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
};
componentDidUpdate(prevProps, prevState){
if(prevProps.match.params.name !== this.props.match.params.name){
Api.get(`category/${categoryName}`).then(
response => {
this.setState({products: response.data});
});
}
}
render(){
return (
<div>
<div className="ref">
<div className="menu-hr"></div>
<div className="menu-cat">
<div className="menu-catname ">BESTSELLERS</div>
</div>
</div>
<div className="card-container">
<div className="all-cards" data-label="Bestsellers">
<Card />
</div>
</div>
</div>
);
}
};
export default Products;
If you want to force rerenders anyway and componentDidUpdate doesnt works for you, you can cause force rerender using key prop
import React from 'react';
import Products from './Products';
class CategoryProducts extends React.Component {
render(){
return (
<div className="content-wrapper">
<div className="menu-left">
<Products key={this.props.match.params.name}/>
</div>
</div>
);
}
}
export default CategoryProducts;
Please let me know if ut didnt solve your problem.
I am trying to have a Link, when clicked, auto-scroll to the position of component. It is currently working 1, though a type error "TypeError: this.props.parentMethod is not a function" is thrown after the link/scroll is successful.
I have a set of links in a Header component, where clicking the links would jump to the listed components on the same page (SPA). I was also trying to pass the functions between components, though the Link + Scroll won't function without part of this code 2.
Heres the layout I currently have, not sure what is causing this TypeError. I am only trying to make the link for /About work at the moment.
App.jsx:
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router} from 'react-router-dom';
import Header from './components/Header.jsx'
import Footer from './components/Footer.jsx'
import Main from './components/Main.jsx'
import About from './components/About.jsx'
import Content from './components/Content.jsx'
import Portfolio from './components/Portfolio.jsx'
import './assets/styles.css';
class App extends Component {
constructor (props){
super(props);
console.log("app");
}
render() {
return (
<Router>
<div className="Global">
<div className="BG-1">
<div className="Header"><Header/></div>
<div className="Main"><Main /></div>
<div className="About"><About/></div>
</div>
<div className="BG-2">
<div className="Content"><Content/></div>
<div className="Portfolio"><Portfolio /></div>
</div>
<div className="Footer"><Footer /></div>
</div>
</Router>
);
}
}
export default App;
Header.jsx:
import React, { Component} from 'react';
import { Collapse, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink } from 'reactstrap';
import { Route, Link, Switch, BrowserRouter as Router } from 'react-router-dom';
import App from '../App.jsx'
import About from '../components/About.jsx'
import '../assets/styles.css';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faUserAstronaut } from '#fortawesome/free-solid-svg-icons'
class Header extends Component {
constructor (props){
super(props);
console.log('header');
}
click = () => {
console.log('The link was clicked.');
this.props.parentMethod();
}
render() {
return(
<Router>
<div>
<Navbar className="Header-header" light expand="md">
<Nav className="ml-auto" navbar>
<NavItem>
<Link to='/#about' className="Header-link" onClick={this.click}><NavLink> About </NavLink></Link>
</NavItem>
</Nav>
</Navbar>
</div>
</Router>
)
}
}
export default Header;
About.jsx:
import React, { Component } from 'react';
import { Row, Col, Toast, ToastBody, ToastHeader } from 'reactstrap';
import Header from '../components/Header.jsx'
import '../assets/styles.css';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faAngleDoubleDown } from '#fortawesome/free-solid-svg-icons'
class About extends Component {
constructor (props){
super(props);
this.state = { currOpacity: 1 };
console.log('about');
}
componentDidMount () {
window.onscroll =()=>{
if (window.scrollY < 750){
this.setState({currOpacity: 1})
}
if (750 <= window.scrollY){
const newOpacity = (200 - ((Math.ceil(window.scrollY/ 25)*25) - 750))/200;
this.setState({currOpacity: newOpacity})
}
}
}
newRef() {
console.log("Yo dawg.");
}
render () {
const opacity = Math.min(this.state.currOpacity, 1);
// console.log("scrollY", window.scrollY, (200 - ((Math.ceil(window.scrollY/ 25)*25) - 750))/200)
// console.log("opacity:", opacity)
return (
<div href='/#section-about'>
<span className="Main-arrow" style={{ opacity }}>
<FontAwesomeIcon className="Main-arrow-icon" icon={faAngleDoubleDown} size="3x" />
</span>
<Row className="About-title-row">
<h1 className="About-title" id={'about'} parentMethod={this.newRef}>About Me</h1>
</Row>
</div>
)
}
}
export default About;
Please let me know if more code is needed, some irrelevant content was removed. Any help would be appreciated!
Anthony
1 Click Link to Scroll Method: Click link to scroll to specific section react.js
2 Parent method call from Child: React - Call parent method in child component
You are getting the type error because prop parentMethod is not passed to the Header component.
In your App.jsx file you need to pass a prop to Header Component like this
<Header parentMethod={() => {}} /> then it won't through type error
and you have to create a method in App.jsx file which you want to perform like the one you have created in About.jsx
import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router} from 'react-router-dom';
import Header from './components/Header.jsx'
import Footer from './components/Footer.jsx'
import Main from './components/Main.jsx'
import About from './components/About.jsx'
import Content from './components/Content.jsx'
import Portfolio from './components/Portfolio.jsx'
import './assets/styles.css';
class App extends Component {
constructor (props){
super(props);
console.log("app");
}
newRef() {
console.log("Yo dawg.");
}
render() {
return (
<Router>
<div className="Global">
<div className="BG-1">
<div className="Header"><Header parentMethod={this.newRef}/></div>
<div className="Main"><Main /></div>
<div className="About"><About/></div>
</div>
<div className="BG-2">
<div className="Content"><Content/></div>
<div className="Portfolio"><Portfolio /></div>
</div>
<div className="Footer"><Footer /></div>
</div>
</Router>
);
}
}
export default App;
Update your Header.jsx file as below
click = (link) => {
console.log("The link was clicked.", this.props);
this.props.parentMethod();
window.location = link;
};
and update the link as below
<Link to="/#about" className="Header-link" onClick={() => this.click('/#about')}>
<NavLink> About </NavLink>
</Link>
I want to show ONLY the <Logout/> button from the <Title/> component on the same row of the title but only when the user has made it to <Home/> component.
In other words, I don't want the CSS from <Title/> to be incorporated inside the <Home/> component because then it'll just be repeating itself.
I want it to show on the same row as the title only when they've logged in successfully and they're in <Home/>
How would I go about making this happen?
(If you need more information please let me know or if it's unclear)
Here's Title.js:
import React, {Component} from 'react';
import classes from './Title.css';
import LogoutButton from '../../containers/LogoutButton/LogoutButton';
class Title extends Component {
constructor(props) {
super(props);
this.state = {
showLogoutButton: this.props.authenticated
};
}
render() {
const { showLogoutButton } = this.state;
return(
<div className="row" style={{"display": "flex"}}>
{showLogoutButton && <LogoutButton/>}
<h1 className={classes.Title}>Pick Ups</h1>
</div>
);
}
}
export default Title;
Here's Home.js:
import React, { Component } from 'react';
import classes from './Home.css';
import Title from '../../components/Title/Title';
class Home extends Component {
render() {
return (
<div>
<Title authenticated= {true}/>
</div>
);
}
}
export default Home;
Here's LogoutButton.js:
import React, {Component} from 'react';
import fire from '../../config/Fire';
import classes from './LogoutButton.css';
class LogoutButton extends Component {
logout = () => {
fire.auth().signOut();
};
render() {
return(
<div>
<button className={classes.LogoutButton} onClick={this.logout.bind(this)}>Logout</button>
</div>
);
}
}
export default LogoutButton;
I get an error saying
You must pass a component to the function returned by connect.
Instead received undefined.
I don't know why this is happening. It works with my Checkout.js component, but not my Store.js component. Why is it working for Checkout but not Store? I want to have access to {total} like I do in the Checkout component.
This is my container Store.js
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Store from '../components/Store';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Store);
And this is my component Store.js
import React, {Component} from 'react';
import { PropTypes } from 'react';
import Home from '../components/Home';
import Cart from '../containers/Cart';
import ProductList from '../containers/ProductList';
import Checkout from '../containers/Checkout';
class Store extends Component{
render(){
return(
<div className="container">
<div className="row">
<div className="col-md-12">
<h3>Armor and Weapon Store</h3>
<h4 className="badge badge-warning margin-right">Gold: </h4>
</div>
</div>
<div className="row">
<div className="col-md-8">
<ProductList />
</div>
<div className="col-md-4">
<Cart />
<Checkout />
</div>
</div>
</div>
);
}
}
Store.propTypes = {
total: PropTypes.number,
}
export default Store;
Here is the container Checkout.js that works
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Checkout from '../components/Checkout/Checkout';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Checkout);
And the component Checkout.js
import React, { PropTypes } from 'react';
import {Component} from 'react';
import Home from '../components/Home.js';
class Checkout extends Component{
buttonClick = () => {
let { total } = this.props;
var home = new Home
var max = home.getMax()
console.log(total);
console.log(max);
if (max >= total) {
max = max - total;
console.log(max);
}
else {
console.log('Not enough gold!');
}
}
render() {
return(
<div>
<button type="button" onClick={this.buttonClick}> Checkout </button>
</div>
);
}
}
Checkout.propTypes = {
total: PropTypes.number,
}
export default Checkout;