Create routes on dynamic menu bar in react js - javascript

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.

Related

React Components not showing using Router, Route, Link

React Components not showing using Router, Route, Link
By clicking the Menu button I can tell from the URL: "http://localhost:3000/Menu", that I have linked to the right route. However, the Menu component just won't show up.
Here is the code for my NavBar Component:
import React, {Component} from 'react';
import './index.css'
import logo from '../../image/laoma-logo.png'
import {NavItems} from "./NavItems/NavItems";
import {Link} from "react-router-dom";
class HeaderNav extends Component {
state = {clicked: false}
handleClick = () =>{
this.setState({clicked: !this.state.clicked})
}
render() {
return (
<nav className="NavItems">
<div>
<img className="NavLogo" src={logo} alt='LaoMa Logo'/>
</div>
<div className="menu-icon" onClick={this.handleClick}>
<i className={this.state.clicked ? 'fas fa-times':'fas fa-bars'}>
</i>
</div>
<ul className={this.state.clicked? 'nav-menu active': 'nav-menu'}>
{NavItems.map((item, index)=> {
return (
<li key={index}>
<Link className={item.cName} href={item.url} to={item.title}>
{item.title}
</Link>
</li>
)
})}
</ul>
</nav>
);
}
}
export default HeaderNav;
Here is my Menu component,
import React, {useState} from 'react';
import items from "../../../data/items";
import Categories from "./Categories";
import Items from "./Items";
import './index.css'
const allCategories = ['all', ...new Set(items.map((item) => item.category))];
function Menu() {
const [menuItems, setMenuItems] = useState(items);
const [categories] = useState(allCategories);
const filterItems = (category) => {
if (category === 'all') {
setMenuItems(items);
return;
}
const newItems = items.filter((item) => item.category === category);
setMenuItems(newItems);
};
return (
<main>
{/* <Route path={NavItems.title} component={Menu}/> */}
<section className='menu section'>
<Categories categories={categories} filterItems={filterItems}/>
<Items items={menuItems}/>
</section>
</main>
);
}
export default Menu;
Here is my App components:
import HeaderNav from './components/HeaderNav/index';
import {Component} from "react";
import { BrowerRouter as Router, Route} from 'react-router-dom';
import './App.css';
import Menu from './components/Body/Menu';
export default class App extends Component {
render() {
return (
<div className="App">
<Router>
<HeaderNav/>
<Route path='/Menu'>
<Menu/>
</Route>
</Router>
</div>
);
}
}
Just from the sake of completion, here is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
I realized that I should use exact path='' instead of path='' because how router works is that it will go through every routes and apply the very first one in the list. And with partial matching, it will return the component or page pf the first nested route, and here 'exact' comes into play and solve the issue.

how to change Navbar based on role with jwt token reactjs

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;

URL redirect from event handlers in React v4

I am new to React, and I am having an issue redirecting to a new page using JavaScript event handlers. I don't know what I am not getting right.
App.js
import React, { Component } from 'react';
import {Switch, Route} from 'react-router-dom';
import Nav, {Jumbotron} from '../partials/headobjs';
import Footer from '../partials/footer';
import Users from '../components/user';
import UserObj from '../components/userobj';
import Err404 from '../components/err404';
//import css files..
import '../css/styles.css';
class App extends Component {
render() {
return (
<div>
<Nav />
<Jumbotron/>
<Switch>
<Route exact path='/' component={Users}/>
<Route path='/user' component={UserObj}/>
<Route component={Err404} />
</Switch>
<div className='clr'></div>
<Footer />
</div>
);
}
}
export default App;
Users.js
import React, { Component } from 'react';
import {Redirect} from 'react-router-dom';
class Users extends Component {
constructor(){
super();
this.state = {
name:aminu
};
}
gotoURL(usr){
let url = `/user/${usr}`;
//console.log(url);
return <Redirect to={url}/>
}
render() {
return (
<div className="container">
<button onClick={this.gotoURL.bind(this, this.state.name)}>
Go to {this.state.name} page
</button>
</div>
);
}
}
export default Users;
I want the function gotoURL to redirect to a new route, but I'm not sure what I am doing wrong, I have tried using the browserHistory, and now I'm trying out the <Redirect/> class but yet to no avail.
Redirect component needs to be rendered and not returned to the onClick handler which is why it is not working. You can make use of history.push instead
gotoURL(usr){
let url = `/user/${usr}`;
//console.log(url);
this.props.history.push(url);
}
Instead of redirect from function, use render method and state to workout with redirect problem
class Users extends Component {
constructor(){
super();
this.state = {
name:'aminu',
toUser: false
};
}
gotoURL(usr){
let url = `/user/${usr}`;
//console.log(url);
this.setState({toUser:true, goto: url})
}
render() {
if (this.state.toUser === true) {
return <Redirect to={this.state.goto}/>
}
return (
<div className="container">
<button onClick={this.gotoURL.bind(this, this.state.name)}>
Go to {this.state.name} page
</button>
</div>
);
}
}
You can use Link component from react-v4 to change your route.
import { Link } from 'react-router-dom';
<div className="container">
<Link to={`/user/${usr}`}
<button>
Go to {this.state.name} page
</button>
</Link>
</div>

React-Paginate is not clickable

I have been trying to use React-paginate library for pagination, however, the buttons formed by it is not clickable,i don't understand what i am doing wrong
And there are no example given, or no question asked
What would be the correct way of using this pagination
Here is the code of my App.js
import React, { Component } from 'react';
import './App.css';
import Navbar from '../src/components/navbar/navbar'
import SearchIt from '../src/components/searchField/search'
import Container from 'react-bootstrap/Container'
import Card from '../src/components/cards/cards'
import Axios from 'axios'
import Pagination from '../src/components/pagination/paginating'
class App extends Component {
state={
fetchedData:[]
}
componentDidMount(){
Axios.get('http://localhost:3000/1').then((responseData)=>{
//console.log(responseData.data)
this.setState({fetchedData:responseData.data})
}).catch((err)=>{
console.log(err)
})
}
handlePageClicked = data => {
let selected = data.selected;
console.log(selected)
};
render() {
return (
<div className="App">
<Navbar/>
<Container>
<SearchIt/>
<Card data={this.state.fetchedData}/>
<Pagination handlePageClick={this.handlePageClicked}/>
</Container>
</div>
);
}
}
export default App;
And here is the code for paginating.js
import React,{Component} from 'react'
import ReactPaginate from 'react-paginate';
import './paginateStyle.css'
const page = (props)=>{
return(
<ReactPaginate
previousLabel={'previous'}
nextLabel={'next'}
breakLabel={'...'}
breakClassName={'break-me'}
pageCount={10}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={props.handlePageClick}
containerClassName={'pagination'}
subContainerClassName={'pages pagination'}
activeClassName={'active'}
/>
)
}
export default page
These button are not clickable
I did a quick sample and it worked.
import ReactPaginate from 'react-paginate';
const Pagination = (props) => {
return (
<ReactPaginate
previousLabel={'previous'}
nextLabel={'next'}
breakLabel={'...'}
breakClassName={'break-me'}
pageCount={10}
marginPagesDisplayed={2}
pageRangeDisplayed={5}
onPageChange={props.handlePageClick}
containerClassName={'pagination'}
subContainerClassName={'pages pagination'}
activeClassName={'active'}
/>
)
}
class App extends Component {
state = {
selectedPage: 0
}
handlePageClicked = data => {
let selected = data.selected;
this.setState({
selectedPage: selected
})
console.log(selected)
};
render() {
return (
<React.Fragment>
<div>You selected: {this.state.selectedPage}</div>
<div className="App">
<Pagination handlePageClick={this.handlePageClicked} />
</div>
</React.Fragment>
);
}
}
There could be something in paginateStyle.css which is making the Pagination not work properly or some other CSS in your application.
EDIT:
From comments, a ui component with higher z index was over them and was not visible/clickable

how to only make logout button appear with no CSS from a separate component

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;

Categories