I'm having an issue with the code
TypeError: Cannot set property 'props' of undefined
i think i did everything right. I even referenced
react cannot set property of props of undefined
and
React-router: TypeError: Cannot set property 'props' of undefined
was unable to figure out the error.
import React from 'react';
import {BrowserRouter as Router, Route, Link} from "react-router-dom";
import signUp from './signUp';
import signIn from './signIn';
import Users from './Users';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import Button from '#material-ui/core/Button';
import {withStyles} from '#material-ui/core';
import Dashboard from './dashBoard';
import { connect } from 'react-redux';
import { createBrowserHistory } from 'history';
import PropTypes, { func, bool, string} from 'prop-types';
export const history = createBrowserHistory({forceRefresh: true});
const styles = {
// This group of buttons will be aligned to the right
rightToolbar: {
color: '#fff',
textDecoration: 'none',
a: {
color: '#fff'
}
},
rightt: {
marginLeft: 'auto',
marginRight: 24
},
root: {
flexGrow: 1
},
menuButton: {
marginRight: 16,
marginLeft: -12
}
};
const logout = (e) => {
e.preventDefault();
localStorage.removeItem('JWT');
};
const Navbar = ({classes, props}) => (
<Router history={history}>
<div className={classes.root}>
<AppBar position="static" className={classes.navbar}>
<Toolbar>
<IconButton color="inherit" aria-label="Menu">
<MenuIcon/>
</IconButton>
<Typography variant="h6" color="inherit">
Eli App
</Typography>
<Typography classcolor="inherit" className={classes.rightt}>
{!props.token && (
<Button>
<Link to="/signUp" className={classes.rightToolbar} >
Sign Up
</Link>
</Button>
)}
<Button>
<Link to="/users" className={classes.rightToolbar}>
Users
</Link>
</Button>
<Button>
<Link to="/dashboard" className={classes.rightToolbar}>
Dashboard
</Link>
</Button>
<Button
onClick={logout}
>
<Link className={classes.rightToolbar} to={'/'}>
LogOut
</Link>
</Button>
</Typography>
</Toolbar>
</AppBar>
<Route path="/signUp" component={signUp}/>
<Route path="/signIn" component={signIn}/>
<Route path="/users" component={Users}/>
<Route path="/dashboard" component={Dashboard}/>
<Route path="/signOut"/>
</div>
</Router>
);
const mapStateToProps = (state) => ({
token: state.user.getToken
})
const mapDispatchToProps = (dispatch) => ({
// logIn: (user) => dispatch(logIn(user))
});
Navbar.propTypes = {
token:PropTypes.string,
}
// export default withStyles(styles)(Navbar);
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles))(Navbar);
updated
Th values you are deconstructing in your function's arguments are already your props, if you want to access your token, you can do the following :
const Navbar = ({classes, token}) => ( //classes and token are INSIDE your props
In the render function :
{!token && (
It seems like the problem could also come from your export :
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles))(Navbar);
You should use compose to use multiple HOC together :
import { compose } from 'redux'
//....
export default compose(connect(mapStateToProps, mapDispatchToProps), withStyles(styles))(Navbar);
You may also experience some unexpected behavior when using a stateless function with redux, I suggest also using the solution from #Shalini Sentiya.
Try to using the navbar react class instead of the function
class Navbar extends Component {
constructor(props){
super(props);
}
render() {
const { token } = this.props;
return (
<Router history={history}>
// your code
{!token && (
<Button>
<Link to="/signUp" className={classes.rightToolbar} >
Sign Up
</Link>
</Button>
)}
// your code
</Router>
);
}
}
const mapStateToProps = (state) => ({
token: state.user.getToken
})
const mapDispatchToProps = (dispatch) => ({
// logIn: (user) => dispatch(logIn(user))
});
Navbar.propTypes = {
token:PropTypes.string,
}
// export default withStyles(styles)(Navbar);
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles))(Navbar);
Related
I am not sure what went wrong with my react app below, it compile successfully without error but doesn't show anything (just show a blank page). Can anyone point out what went wrong with my code? Sorry I am new to react.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'
import { BrowserRouter } from 'react-router-dom'
import App from './App';
ReactDOM.render((
// <Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
// </Provider>
), document.getElementById('root'))
App.js
import { BrowserRouter as Router, Route, Link, NavLink } from "react-router-dom";
import Home from "./components/Home";
import NewBuilding from "./components/NewBuilding";
import React, { Component } from "react";
import Web3 from 'web3';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import "./App.css";
import { useEffect, useState } from 'react';
function App() {
const [currentAccount, setCurrentAccount] = useState(null);
const checkWalletIsConnected = async () => {
const { ethereum } = window;
if (!ethereum) {
console.log("Make sure you have Metamask installed!");
return;
} else {
console.log("Wallet exists! We're ready to go!")
}
const accounts = await ethereum.request({ method: 'eth_accounts' });
if (accounts.length !== 0) {
const account = accounts[0];
console.log("Found an authorized account: ", account);
setCurrentAccount(account);
} else {
console.log("No authorized account found");
}
}
const connectWalletHandler = async () => {
const { ethereum } = window;
if (!ethereum) {
alert("Please install Metamask!");
}
try {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
console.log("Found an account! Address: ", accounts[0]);
setCurrentAccount(accounts[0]);
} catch (err) {
console.log(err)
}
}
const connectWalletButton = () => {
return (
<button onClick={connectWalletHandler} className='cta-button connect-wallet-button'>
Connect Wallet
</button>
)
}
useEffect(() => {
checkWalletIsConnected();
}, [])
return (
<div>
<Router>
<AppBar position="static" color="default" style={{ margin: 0 }}>
<Toolbar>
<Typography variant="h6" color="inherit">
<NavLink className="nav-link" to="/">Home</NavLink>
</Typography>
<NavLink className="nav-link" to="/new/">New</NavLink>
</Toolbar>
</AppBar>
<Route path="/" exact component={Home} />
<Route path="/new/" component={NewBuilding} />
</Router>
</div>
)
}
export default App;
My Home.js is residing in a components folder
The folder structure is as below
Home.js
import React, { useState, useEffect } from "react";
import { makeStyles } from '#material-ui/core/styles';
import Web3 from 'web3'
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1),
},
input: {
display: 'none',
},
}));
const Home = () => {
const classes = useStyles();
const [ contract, setContract] = useState(null)
const [ accounts, setAccounts ] = useState(null)
const [ funds, setFunds ] = useState([])
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
useEffect(() => {
}, []);
return (
<div><h2>Home</h2></div>
)
}
export default Home;
Your Route component should have the prop element instead of component, see the migration guide.
<Route path="/" exact element={<Home />} />
In App.js you're wrapping your components again in a Router. Instead you should wrap your Route components in a Routes.
import { Routes, Route, Link, NavLink } from "react-router-dom";
...
<div>
<AppBar position="static" color="default" style={{ margin: 0 }}>
<Toolbar>
<Typography variant="h6" color="inherit">
<NavLink className="nav-link" to="/">
Home
</NavLink>
</Typography>
<NavLink className="nav-link" to="/new/">
New
</NavLink>
</Toolbar>
</AppBar>
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/new/" element={<NewBuilding />} />
</Routes>
</div>
I am a beginner in ReactJS and React Router and I am having some issues with my nested router.
For my main router in App.js, things work well. So I can visit my landing page (/), login page (/login), and register page (/register). And once I reach this page, if I do a manual refresh on my Chrome Browser (ctrl r), the page refresh and render accordingly.
Below is my App.js
import React from "react";
import { Router, Switch } from "react-router-dom";
import Login from "./components/Login";
import Register from "./components/Register";
import Dashboard from "./components/Dashboard";
import DynamicLayout from './router/DynamicLayout';
import LandingPage from './components/homepage/LandingPage';
import { history } from "./helpers/history";
const App = () => {
return (
<Router history={history}>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={LandingPage}
layout="LANDING_NAV"
/>
<DynamicLayout
exact
path="/login"
component={Login}
layout="LOGIN_PAGE"
/>
<DynamicLayout
exact
path="/register"
component={Register}
layout="REGISTER_PAGE"
/>
<DynamicLayout
path="/dashboard"
component={Dashboard}
layout="DASHBOARD_PAGE"
/>
</Switch>
</div>
</Router>
);
};
export default App;
Below is my DynamicLayout.js
import React from "react";
import { BrowserRouter as Route, Switch } from "react-router-dom";
import Login from "../components/Login";
import Register from "../components/Register";
const DynamicLayout = (props) => {
const { component: RoutedComponent, layout, ...rest } = props;
const actualRouteComponent = <RoutedComponent {...props} />;
switch (layout) {
case "LANDING_NAV": {
return <div>{actualRouteComponent}</div>;
}
case "LOGIN_PAGE": {
return <div>{actualRouteComponent}</div>;
}
case "REGISTER_PAGE": {
return <div>{actualRouteComponent}</div>;
}
case "DASHBOARD_PAGE": {
return <div>{actualRouteComponent}</div>;
}
default: {
return (
<div>
<h2>Default Nav</h2>
{actualRouteComponent}
</div>
);
}
}
};
export default DynamicLayout;
The issue is with my nested router which is in my Dashboard component. Basically, once a admin user logged in, they will be shown the admin dashboard.
Below is my Dashboard component.
import React, { useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { history } from "../helpers/history";
import { useHistory } from 'react-router-dom';
import {
BrowserRouter as Router,
Route,
Switch,
} from "react-router-dom";
import { logout } from "../actions/auth";
import AdminSideNavBar from "../components/admin/AdminSideNavBar";
import AdminManageUsers from "./admin/AdminManageUsers";
import AdminPendingApprovalUsers from "../components/admin/AdminPendingApprovalUsers";
import AdminDeactivatedUsers from "./admin/AdminDeactivatedUsers";
import AdminRegisterInternalUsers from "./admin/AdminRegisterInternalUsers";
import AdminLogs from "../components/admin/AdminLogs";
import BrokerSideNavBar from "../components/broker/BrokerSideNavBar";
import ShareholderSideNavBar from "../components/shareholder/ShareholderSideNavBar";
import Login from "../components/Login"
import AdminActivatedUsers from "./admin/AdminActivatedUsers";
const Dashboard = () => {
const [showAdminDashboard, setShowAdminDashboard] = useState(false);
const [showBrokerDashboard, setShowBrokerDashboard] = useState(false);
const [showShareholderDashboard, setShowShareholderDashboard] =
useState(false);
const { user: currentUser } = useSelector((state) => state.auth);
const dispatch = useDispatch();
useEffect(() => {
if (currentUser) {
setShowAdminDashboard(currentUser.roles.includes("ROLE_ADMIN"));
setShowBrokerDashboard(currentUser.roles.includes("ROLE_BROKER"));
setShowShareholderDashboard(
currentUser.roles.includes("ROLE_SHAREHOLDER")
);
}
}, [currentUser]);
const logOut = () => {
dispatch(logout());
};
let history = useHistory();
return (
<div>
{showAdminDashboard && (
<Router history= {history}>
<div className="wrapper">
<AdminSideNavBar />
<Switch>
<Route exact path="/dashboard" component={AdminPendingApprovalUsers} />
<Route exact path="/logs" component={AdminLogs} />
<Route exact path="/manageusers" component={AdminManageUsers} />
<Route exact path="/activeusers" component={AdminActivatedUsers} />
<Route exact path="/deactivatedusers" component={AdminDeactivatedUsers} />
<Route exact path="/registerinternalusers" component={AdminRegisterInternalUsers} />
</Switch>
</div>
</Router>
)}
{showBrokerDashboard && <BrokerSideNavBar />}
{showShareholderDashboard && <ShareholderSideNavBar />}
</div>
);
};
export default Dashboard;
With my side nav bar (AdminSideNavbar component), I can navigate to the various pages. Like /logs, /manageusers, /activeusers etc.
Below is my AdminSideNavBar component
import React from "react";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { logout } from "../../actions/auth";
import {
CDBSidebar,
CDBSidebarContent,
CDBSidebarFooter,
CDBSidebarHeader,
CDBSidebarMenu,
CDBSidebarMenuItem,
} from "cdbreact";
import { NavLink } from "react-router-dom";
const AdminSideNavBar = () => {
const { user: currentUser } = useSelector((state) => state.auth);
const dispatch = useDispatch();
const { isLoggedIn } = useSelector((state) => state.auth);
const logOut = () => {
dispatch(logout());
};
return (
<div className="stickysidenav">
<CDBSidebar textColor="#fff" backgroundColor="#333">
<CDBSidebarHeader prefix={<i className="fa fa-bars fa-large"></i>}>
<a
href="/"
className="text-decoration-none"
style={{ color: "inherit" }}
>
TradeDuh
</a>
<p>{currentUser.username}</p>
{/* {isLoggedIn && (
<div className="wrapper">
<p>{currentUser.username}</p>
</div>
)} */}
</CDBSidebarHeader>
<CDBSidebarContent className="sidebar-content">
<CDBSidebarMenu>
<NavLink exact to="/dashboard" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="columns">Dashboard</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/logs" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="table">Logs</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/uploadcompany" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="edit">Update Nasdaq Stocks</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/manageusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="users-cog">Manage Users</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/activeusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-check">Active Users</CDBSidebarMenuItem>
</NavLink>
<NavLink exact to="/deactivatedusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-times">De-activated Users</CDBSidebarMenuItem>
</NavLink>
<NavLink to="/registerinternalusers" activeClassName="activeClicked">
<CDBSidebarMenuItem icon="user-plus">
Add Internal Users
</CDBSidebarMenuItem>
</NavLink>
<NavLink
exact
to="/login"
activeClassName="activeClicked"
onClick={logOut}
>
<CDBSidebarMenuItem icon="sign-out-alt">
Log Out
</CDBSidebarMenuItem>
</NavLink>
</CDBSidebarMenu>
</CDBSidebarContent>
<CDBSidebarFooter style={{ textAlign: "center" }}>
<div
style={{
padding: "20px 5px",
}}
>
TradeDuh (FDM - S21-Java-02)
</div>
</CDBSidebarFooter>
</CDBSidebar>
</div>
);
};
export default AdminSideNavBar;
The issue is, once I reach the various page, if I do a manual refresh (ctrl r), my whole screen will turn white/blank.
So say if I click on /logs, AdminLogs component is rendered, which is all good. BUT... if I now press ctrl r to do a manual fresh, the AdminLogs component don't show anymore. All I see is a blank white screen.
This is totally different from what is happening in my main router where I can do a manual page fresh and the page will render accordingly.
Any idea on how to solve this? What is my issue here?
Thank you for the help!
i am trying create a transition screen from one page to the other
function MainPage(){
return (
<div>
{pagestate.navigating == "true" ? (
<FadeIn>
<div className="d-flex justify-content-center align-items-center">
<h1>signing you in ....</h1>
<Link to="/" color="black" >sign in</Link>
{pagestate.loading =="false" ? (
<Lottie options={defaultOptions} height={120} width={120} />
) : (
<Lottie options={defaultOptions2} height={220} width={120} />
)}
</div>
</FadeIn>
) : (
<div>
<h1>hello world</h1>
<Link to="/" color="black" >sign in</Link>
</div>
)}
The code works fine but I want it to navigate to /page2 when pagestate.loading = "false". I was able to achieve the page navigation with using
const history = useHistory()
then call navigation like
history.push('/page2')
I tried couple of method but could not get it work inside the transition logic.
How can I incorporate to the navigation into a new page after loading state has been changed to false in the transition logic above?
Encountered that a couple of days ago, i found a solution to it but it’s kinda weird,i’ve done it using redux, i’ve made a Link Component Called LinkWithAnimation,created a reducer as RouteReducer which will store current transition state, 2 states:
First one is For Transitioning In.
Second one is For Transitioning Out.
Wrapped my application with a div and passed the Transition that’s stored in redux, everytime LinkWithAnimation Is clicked This Is What Happens:
Dispatch An Action For Transitioning In
Wait(Delay) Till the Transition Has Finished(Depending On The Duration Of It)
Dispatch An Action for Transitioning Out.
And then push the new path using History API.
Note: Make Use Of Redux Thunk.
ActionTypes.js
export const ActionsType = {
...otherActions,
ANIMATION_IN: "animation-in",
ANIMATION_OUT: "animation-out",
};
ActionsCreator.js
import { ActionsType } from "./ActionsType.js";
import { history } from "../index.js";
export const ActionsCreator = {
...otherActionCreators,
userLogout: () => ({ type: ActionsType.LOGOUT }),
animateIn: () => ({ type: ActionsType.ANIMATION_IN }),
animateOut: () => ({ type: ActionsType.ANIMATION_OUT }),
pageTransition: (duration, path) => {
return async (dispatch) => {
const delay = async () => {
return new Promise((resolve) => setTimeout(resolve, duration));
};
dispatch(ActionsCreator.animateOut());
await delay();
dispatch(ActionsCreator.animateIn());
history.push(path);
};
},
};
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
ReactDOM.render(
<Router history={history}>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById("root")
);
LinkWithAnimation.js
import React, { useRef, useEffect } from "react";
import { Link } from "react-router-dom";
import { ActionsCreator } from "../actions/ActionsCreator.js";
import { connect } from "react-redux";
const LinkWithAnimation = ({
className,
additionalFunction,
PageTransitioning,
to,
children,
style,
component,
ReactTo,
disabled,
}) => {
const LinkRef = useRef();
// This Effect To Handle Page Transition Once The User Is Signed In
useEffect(() => {
if (ReactTo === true) {
LinkRef.current.click();
}
}, [ReactTo]);
const componentProp =
component !== undefined
? {
component: component,
}
: {};
return (
<>
<Link
onClick={async () => {
if (disabled) return;
PageTransitioning(230, to);
if (additionalFunction !== undefined) {
additionalFunction();
}
}}
ref={LinkRef}
className={className}
style={{ ...style }}
{...componentProp}
>
{children}
</Link>
</>
);
};
const mapDispatchToProps = (dispatch) => ({
PageTransitioning: (duration, path) => {
dispatch(ActionsCreator.pageTransition(duration, path));
},
});
export default connect(null, mapDispatchToProps)(LinkWithAnimation);
Main.js
import React, { Fragment } from "react";
import { Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import Homepage from "./Homepage/Homepage.js";
import Signup from "./Signup/Signup.js";
import UserInterface from "./UserInterface/UserInterface.js";
import { SignIn } from "./SignIn/SignIn.js";
import { useRouteTransitionScroll } from "../hooks/useRouteTransitionScroll.js";
const Main = ({ keyframe }) => {
useRouteTransitionScroll({
from: "/signup",
to: "/home",
scroll_y: 650,
});
return (
<Switch component={Fragment}>
<div
style={{
animationName: keyframe,
animationDuration: "250ms",
animationTimingFunction: "linear",
}}
>
<Route path="/mainpage">
<UserInterface />
</Route>
<Route path="/home">
<Homepage />
</Route>
<Route path="/signin">
<SignIn />
</Route>
<Route path="/signup">
<Signup />
</Route>
</div>
</Switch>
);
};
const mapStateToProps = (state) => ({
keyframe: state.Route.animationName,
});
export default connect(mapStateToProps)(Main);
I have react-App with redux using Asp.netWebApi as back-end. The site has tutors.jsx and tutorDetails.jsx components. When the user clicks on the tutors list in tutors.jsx component , the tutorDetails.jsx component displays.
The link has two parameters in url tutorId and fullName. like
https://www.virtualcollege.pk/TutorDetails/1105/Sohail%20Anjum
The problem is that when we copy the url and open it in a new browser tab, it does not work.
here is live link for tutors:
tutors list live link
Here is the live link for detail page: the tutorsDetails page live link
Here is code for tutorDetails.jsx component
import React, { useState, useEffect } from "react";
import { makeStyles } from '#material-ui/core/styles';
import {useDispatch,useSelector} from 'react-redux';
import { Link,useParams} from 'react-router-dom';
import * as actions from "../_actions/tutorActions";
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles({
title: {
fontSize: 14,
display: 'flex',
},
pos: {
marginBottom: 12,
},
card: {
padding:10,
marginTop:10,
display: 'flex',
flex:1,
},
cardAction: {
display: 'block',
textAlign: 'initial'
},
cardMedia: {
width: 160,
},
});
export default function TutorDetails(props) {
const [loading, setLoading] = useState(true);
let {tutorId}=useParams(); // get tutorId from url parameter
let {fullName}=useParams();// get fullname from parameter
const dispatch = useDispatch();
const classes = useStyles();
const tutor = useSelector(state=>state.tutor.list)
useEffect(() => {
//call the action creator with dispatch
// and wait until the promise resolves
actions
.fetchById(tutorId)(dispatch)
setLoading(false);
}, []);
return (
<div>{loading === true ? <span>Loading ! Please waite...</span>:<div>
<Card className={classes.card} variant="outlined">
<CardContent>
<Typography variant="h5" component="h2">
{tutor[0].fullName} <br/>
</Typography>
<Typography variant="h5" component="h2">
{tutor[0].Qualification}
</Typography>
<Typography className={classes.title} color="textSecondary" gutterBottom>
category: {tutor[0].category}
</Typography>
<Typography variant="body2" component="p">
experience:{tutor[0].experience}<br/>
subject: {tutor[0].subject}<br/>
Mobile: 0343-3969030<br/>
email: virtualcollegepk01#gmail.com<br/>
city: {tutor[0].city}<br/>
</Typography>
</CardContent>
</Card>
</div>}
</div>
);
}
Here is the link of url in tutors.jsx component.
<Link to={`/TutorDetails/${record.tutorId}/${record.fullName}`}
> {record.fullName}</Link>
Here is the router link in App.js
<Route path="/TutorDetails/:tutorId/:fullName" component={TutorDetails} />
the App.js component is as below:
import React, { useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { history } from '../_helpers';
import { alertActions } from '../_actions/alert.actions';
import { PrivateRoute} from '../_components/PrivateRoute';
import {TeacherCourses} from '../_components/TeacherCourses';
import TutorDetails from '../_components/TutorDetails';
import Tutors from '../_components/Tutors';
import { HomePage } from '../HomePage';
import { Container } from "#material-ui/core";
import { ThemeProvider } from '#material-ui/core/styles'
import CssBaseline from '#material-ui/core/CssBaseline'
import theme from '../theme'
import { ToastProvider} from "react-toast-notifications";
import NewNavbar from "../_components/Header/NewNavbar";
import Footer from "../_components/Header/Footer";
import {carousel} from "react-responsive-carousel/lib/styles/carousel.min.css";
function App() {
const alert = useSelector(state => state.alert);
const dispatch = useDispatch();
useEffect(() => {
history.listen((location, action) => {
// clear alert on location change
dispatch(alertActions.clear());
});
}, []);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<ToastProvider autoDismiss={true}>
<Container maxWidth="lg">
{alert.message &&
<div className={`alert ${alert.type}`}>{alert.message}</div>
}
<Router history={history}>
<div>
<NewNavbar/>
<Switch>
<Route path="/TutorDetails/:tutorId/:fullName" component= {TutorDetails} />
<Route path="/Tutors" component= {Tutors} />
<Route path="/MyCourses/:tutorId/" component= {MyCourses} />
<Route path="/Enroll/:courseId/:courseTitle" component={Enroll} />
<Route path="/" component={HomePage} />
<Redirect from="*" to="/" />
</Switch>
<Footer/>
</div>
</Router>
</Container>
</ToastProvider>
</ThemeProvider>
);
}
export {App} ;
I have a navbar for all pages. I want to make a cart in it, however, when I go to the internal product page, the props that I transmit are not displayed.
Why is this happening ?
I think this is my problem React router v4 not working with Redux
but how i can implement this ?
What do you think ?
App.js
import React, {Component} from 'react';
import {Container} from 'reactstrap';
import {
BrowserRouter,
Route,
Switch
} from "react-router-dom";
import './App.css';
import NavbarMenu from './components/navbar'
import Main from './components/main';
import Good from './components/good';
class App extends Component {
render() {
return (
<BrowserRouter>
<div className="App">
<NavbarMenu/>
<Container>
<Switch>
<Route path="/" exact component={Main}/>
<Route path="/good/:id" component={Good}/>
</Switch>
</Container>
</div>
</BrowserRouter>
);
}
}
export default App;
navbar
import React from 'react';
import {
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
Button
} from 'reactstrap';
import {withRouter} from 'react-router-dom';
import connect from 'react-redux/es/connect/connect';
import {getCart} from '../../redux/actions/cartAction';
class NavbarMenu extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
isOpen: false
};
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
console.log(this.props)
const cartLength = this.props.cart.length;
const cartItems = this.props.cart.map(e => {
return <div key={e.id} style={{marginBottom: '20px'}}>
<DropdownItem
style={{display: 'inline-block', width: 'auto'}}
onClick={() => {
this.props.history.push('/good/' + e.id)
}}>
{e.name}
</DropdownItem>
<Button
style={{display: 'inline-block', float: 'right', marginRight: '20px'}}
color="danger"
>X</Button>
</div>
});
return (
<Navbar
color="light"
light expand="md"
style={{marginBottom: '20px'}}
>
<NavbarBrand
style={{cursor: 'pointer'}}
onClick={() => {
this.props.history.push('/')
}}
>
Shop
</NavbarBrand>
<NavbarToggler onClick={this.toggle}/>
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<UncontrolledDropdown nav inNavbar>
<DropdownToggle nav caret>
Cart: {cartLength} items
</DropdownToggle>
<DropdownMenu right style={{width: '300px'}}>
{cartItems}
<DropdownItem divider/>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
</Collapse>
</Navbar>
);
}
}
const mapStateToProps = state => ({
cart: state.cart.cart
});
export default withRouter(connect(mapStateToProps, {getCart})(NavbarMenu));
Based on the prints you gave, you are opening the item on a diferent window, because of that, the variables on the session in the window are not passed.
One solution you could use is to save pieces of your store that you will need later in the browser localStorage.
You can do that using this by using the Redux subscribe function.
A example could be:
localStorage.js
export const loadState = () => {
try {
const serializedState = localStorage.getItem('state');
if (serializedState === null) return undefined;
return JSON.parse(serializedState);
} catch (err) { return undefined; }
};
export const saveState = (state) => {
try {
const serializedState = JSON.stringify(state);
} catch (err) {
// errors
}
}
And in the redux store you can put:
import { loadState, saveState } from './localStorage';
const persistedState = loadState();
const store = createStore(persistedState);
store.subscribe(() => saveState(store.getState()));
Source: https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage
I solved my problem by adding this code
componentDidMount() {
this.props.getCart();
}