I am trying to access my store from every component page I have, so I followed the following tutorial in order to connect React Router & MobX.
http://frontendinsights.com/connect-mobx-react-router/
However, I am facing a problem at The MobX way – Provider component.
This is the code exmaple:
import { Provider } from 'mobx-react';
import usersStore from './stores/usersStore';
import itemsStore from './stores/itemsStore';
const stores = { usersStore, itemsStore };
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<Route path="/" component={App}>
</Route>
</Router>
</Provider>,
document.getElementById('app')
);
I tried to do the same in index.js
import React from 'react'
import { render } from 'react-dom'
import { Router, hashHistory, Route, IndexRedirect } from 'react-router'
import App from './webapp/App'
import Home from './components/pages/Home'
import Dogs from './components/pages/Dogs'
import Cats from './components/pages/Cats'
import Provider from 'mobx-react'
import RootStore from './webapp/stores'
const store = RootStore
render((
<Provider rootStore={store}>
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRedirect to="/home" />
<Route path="/home" component={Home}/>
<Route path="/dogs" component={Dogs}/>
<Route path="/cats" component={Cats}/>
</Route>
</Router>
</Provider>
), document.getElementById('app'))
However, because of <Provider/>, I am getting an error:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Why am I getting that? It should work doesn't it?
Thanks for any help !
If it's a web app, react-router-dom should be used.
Here is the correct way to inject store with Provider https://github.com/mobxjs/mobx-react#observer
I wrote a solution for your code without using decorator, so it supports create-react-app:
import React, { Component } from 'react';
import { Provider, Observer } from 'mobx-react';
import { observable } from 'mobx';
import { BrowserRouter, Switch, Route, Link, Redirect } from 'react-router-dom';
const myStore = observable({
home: 'Home',
cat: 'Cat',
});
const Home = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.home}</h1></section>)}
/>
);
const Cat = () => (
<Observer
inject={stores => ({ myStore : stores.myStore })}
render={props => (<section><h1>{props.myStore.cat}</h1></section>)}
/>
);
class App extends Component {
render() {
return (
<BrowserRouter>
<Provider myStore={myStore}>
<div className="App">
<header className="App-header">
<nav>
<ul>
<li><Link to="/home">HOME</Link></li>
<li><Link to="/cat">CAT</Link></li>
</ul>
</nav>
</header>
<Switch>
<Route path='/home' exact component={Home} />
<Route path='/cat' exact component={Cat} />
<Redirect from="/" to="/home" />
</Switch>
</div>
</Provider>
</BrowserRouter>
);
}
}
export default App;
All the components are in App.js file. There is no change in default index.js from create-react-app.
Note:
The another way to doing this, it's to simply create a singleton class for the store and use export default new Store() to make it available to all components. The class itself doesn't have to be observable, but its properties do.
Related
im using react router v6 and i every time i use initializing for authentication in my main file it shows this error. i cant find a solution in the internet for it. i want to render some routes only when there is a user but now it doesnt render anything.
AuthNavigator
import React, { useState, useEffect } from 'react';
import app from './firebase';
import { Router, Routes, Route } from 'react-router-dom';
import AuthStack from './stacks/AuthStack';
import AppStack from './stacks/AppStack';
import StaticStack from './stacks/StaticStack';
function AuthNavigator() {
const [initializing, setInitializing] = useState(true);
const [user, setUser] = useState(() => app.auth().currentUser);
useEffect(() => {
const unsubscribe = app.auth().onAuthStateChanged((user) => {
if (user) {
setUser(user);
} else {
setUser(null);
}
if (initializing) {
setInitializing(false);
}
});
// cleanup subscription
return unsubscribe;
}, []);
if (initializing) return 'Loading....';
return (
<Router>
<Routes>
<Route path="*" element={<StaticStack />} />
<Route path="auth/*" element={<AuthStack user={user} />} />
<Route path="app/*" element={<AppStack user={user} />} />
</Routes>
</Router>
);
}
export default AuthNavigator;
App.js
import React from 'react';
import './App.css';
import AuthNavigator from './AuthNavigator';
import { Router } from 'react-router-dom';
function App() {
return (
<Router>
<AuthNavigator />
</Router>
);
}
export default App;
I had the same issue. My issue is because of the following reason.
I had a Header component which consists of NavLink which is a router component. I placed this Header component inside the App component. My App component was like this:
function App() {
return(
<Header/>
<Router>
<Routes>
<Route path="/" element={<Homepage/>}/>
<Route path="/shop" element={<Shop/>}/>
<Route path="/signin" element={<Signin/>}/>
</Routes>
</Router>
)
}
In the above App component, I have placed Header component outside of Router. Since in the Header component I have used NavLink which is a Router component caused this error. Then I moved Header component into the Router component then it worked fine. Finally my code looked like this:
function App() {
return(
<Router>
<Header/>
<Routes>
<Route path="/" element={<Homepage/>}/>
<Route path="/shop" element={<Shop/>}/>
<Route path="/signin" element={<Signin/>}/>
</Routes>
</Router>
)
}
Already wrapped in Router?
if your component is already wrapped in a Router. Make sure you are importing useLocation from react-router-dom instead of react-router. this worked for me.
Make sure that your App component in index.js is wrapped with BrowserRouter like this
const app = (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
In case you run into this problem when running a test, don't forget to wrap your import of App in Router as well. My crude example is below.
import { render, screen } from '#testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { App } from '../App';
test('renders Box', () => {
render(
<BrowserRouter>
<App />
</BrowserRouter>
);
const boxElement = screen.getByLabelText('box-outline');
expect(boxElement).toBeInTheDocument();
});
I had the same error coming up from inside a test. The component I was testing contained a NavLink component, and I wasn't rendering a Router in the test.
This error disappeared after wrapping my component in question with BrowserRouter.
I had this problem when using {useLocation} from 'react-router-dom'
function App() {
const { pathname, hash, key } = useLocation();
//function using pathname hash and key
return(
<Router>
<Header/>
<Routes>
<Route path="/" element={<Homepage/>}/>
<Route path="/shop" element={<Shop/>}/>
<Route path="/signin" element={<Signin/>}/>
</Routes>
</Router>
)
}
throws the same error even with the in the correct place
I fixed it by explicitly wrapping the useLocation() within the router
function App() {
return(
<Router>
<Header/>
<Inner/>
</Router>
)
}
function Inner() {
const { pathname, hash, key } = useLocation();
//function using pathname hash and key
return(
<Routes>
<Route path="/" element={<Homepage/>}/>
<Route path="/shop" element={<Shop/>}/>
<Route path="/signin" element={<Signin/>}/>
</Routes>
)
}
I had this error because Vite was bundling two copies of the same version of react-router-dom... check the outputted bundle for * React Router DOM and see how many copies there are.
If that's the case, the solution will differ. In my scenario I think it's because I was referencing other local npm packages using file:... once I switched to a npm workspace that fixed it.
So i fixed like this structure
index.js
import { BrowserRouter } from 'react-router-dom'
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
App.js
import { Route, Routes, Navigate } from 'react-router-dom'
<Layout>
<Routes>
<Route path="/" element={<Navigate to="/home" />} />
<Route path="/home" element={<Home />} />
{...}
<Route path="*" element={<NotFound />} />
</Routes>
</Layout>
Layout.js
<Fragment>
<Header></Header>
<main className="container">{props.children}</main>
</Fragment>
Header.js
import { Link, NavLink } from 'react-router-dom'
<header className={classes.header}>
<nav>
<NavLink
className={(navData) => (navData.isActive ? classes.active : '')}
to="/search"
>
Search
</NavLink>
</nav>
</header>
App.test.js
import { BrowserRouter } from 'react-router-dom';
it('renders learn react link', async () => {
render(<BrowserRouter><App /></BrowserRouter>)
const linkElement = await screen.findByText(/home/i)
expect(linkElement).toBeInTheDocument()
})
in my case, I faced this error when I used the HOC and context provider and placed my Routing component as the context.provider's child, and export my Provider component by HOC like this:
class Provider extends Component {
render() {
return (
<Context.Provider
value={{
something: this.state.something
}}
>
<Routing />
</Context.Provider>
);
}
}
export default HOC(Provider)
im my case, the problem was putting BrowserRouter inside App.js file, solved it by moving this into index.js file and wrapping it around App.js
Former Index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<React.StrictMode>
<PersistGate persistor={persistor} >
<App/>
</PersistGate>
</React.StrictMode>
</Provider>
);
reportWebVitals();
Former App.js
import { BrowserRouter, Routes, Route, useLocation} from "react-router-dom";
const App = () => {
const {pathname} = useLocation()
return (
<div className='app'>
<BrowserRouter>
<Routes>
<Route path='/*' element={<LandingPage />} />
</Routes>
</BrowserRouter>
</div>
);
};
export default App;
New Index.js
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<React.StrictMode>
<PersistGate persistor={persistor} >
<BrowserRouter >
<App/>
</BrowserRouter>
</PersistGate>
</React.StrictMode>
</Provider>
);
reportWebVitals();
New App.js
import { Routes, Route, useLocation} from "react-router-dom";
const App = () => {
const {pathname} = useLocation()
return (
<div className='app'>
<Routes>
<Route path='/*' element={<LandingPage />} />
<Route path='/registeration' element={<Registration />} />
</Routes>
</div>
);
};
export default App;
Try this:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
am trying to do a route system with react and react-pose for animating route and parsing the location object return me an error can you please help me ?? this is the code the error is in the Routecontainer
import React, { Component } from "react";
import {BrowserRouter, Route, NavLink} from "react-router-dom";
import "./App.css";
import HomeComponent from "./Components/HomeComponent"
import ContactComponent from "./Components/ContactComponent"
import AboutComponent from "./Components/AboutComponent"
import NavBar from "./Components/NavigationBar"
import posed, {PoseGroup} from "react-pose";
const RouteContainer = posed.div({
enter: { opacity: 1, delay: 300, beforeChildren: true },
exit: { opacity: 0 }
});
class App extends Component {
render() {
let {location} = this.props;
return (
<BrowserRouter>
<div>
<NavBar/>
<PoseGroup>
<RouteContainer key={location.key}>
<switch location={location}>
<Route path="/" component={HomeComponent}/>
<Route path="/About" component={AboutComponent}/>
<Route path="/Contact" component={ContactComponent}/>
</switch>
</RouteContainer>
</PoseGroup>
</div>
</BrowserRouter>
);
}
}
export default App;
You are trying to access the location object outside of a Route Component. Since you are using <BrowserRouter> inside the App Component, the HomeComponent, AboutComponent and ContactComponent will have access to the location object but not <App />.
You can read more about where react-router provides the location object here
You can work around this by creating a wrapper component that returns the following:
return (
<BrowserRouter>
<Route path="/" component={App} />
</BrowserRouter>
);
And you can then remove the <BrowserRouter> bit from inside <App />
Component. The path / will match on all the routes since exact={true} is not passed as a prop.
I am following a course where the author has written some code for routing in react using react-router version 3.
<Router history={browserHistory} >
<Route path="/" component={Main}>
<IndexRoute component={PhotoGrid}></IndexRoute>
<Route path="/view/:postId" component={Single}>
</Route>
</Router>
While following the course(in which I am using using router version 4), I came to know that now the <IndexRoute> doesn't exists. I googled for alternative and found that exact is the alternative. But I don't know how to use exact for meeting this requirement. The author want the Main component always on the DOM, and based on the url only the child components should change(i.e Single or PhotoGrid).
I tried below code, which is of course the wrong one:
<BrowserRouter>
<Switch>
<Route path="/" component={Main} />
<Route exact path="/" component={PhotoGrid} />
<Route path="/veiw/:postId" component={Single} />
</Switch>
</BrowserRouter>
My components are:
class Main extends React.Component {
render() {
return (
<div>
<h1>
<Link to="/">Reduxtagram</Link>
</h1>
{React.cloneElement(this.props.children, this.props)}
</div>
);
}
}
class PhotoGrid extends React.Component {
render() {
return <div className="photo-grid">PhotoGrid</div>;
}
}
class Single extends React.Component {
render() {
return <div className="single-photo">Single</div>;
}
}
The Switch component will only render the first Route that is a match.
You could use the Main component as a regular component and use the Switch as children for that.
<BrowserRouter>
<Main>
<Switch>
<Route exact path="/" component={PhotoGrid} />
<Route path="/view/:postId" component={Single} />
</Switch>
</Main>
</BrowserRouter>
i know this is an old question but im following the same course and i decided to update all the libraries, basically i had to restructure the app like this:
reduxtagram.js :
import React from 'react';
import {render} from 'react-dom';
import App from './components/App';
import {Provider} from 'react-redux';
import store from './store';
// import css
import css from './styles/style.styl';
// import react router deps
const router = (
<Provider store={store}>
<App/>
</Provider>
)
render(router , document.getElementById('root'));
main.js:
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import PhotoGrid from './PhotoGrid';
import Single from './Single';
import {Router, Route} from 'react-router-dom';
import {history} from '../store';
export default class Main extends Component {
render() {
return (
<div>
<Router history={history}>
<Route
path="/"
render={(routeProps) => (
<h1>
<Link to='/'>Reduxstagram </Link>
</h1>
)}/>
<Route
path="/grid"
render={(routeProps) => (
<PhotoGrid {...routeProps} {...this.props} />
)}/>
<Route
path="/grid/view/:postID"
render={(routeProps) => (
<Single {...routeProps} {...this.props} />
)}/>
</Router>
</div>
)
}
}
I am trying to setup my react app.
I am trying to understand how to integrate the routes with the app.
When I try to use AppRouter in my ReactDOM, I get an error message that says I shouldn't use Route outside the Router.
I don't understand what the error means. I can get rid of the error message when I remove the AppRouter line from my Provider, but that only creates a new error with the provider. I can't find an example of how to get started.
My app.js has:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import AppRouter from './routers/AppRouter.js';
import { BrowserRouter } from 'react-router-dom';
import configureStore from './store/configureStore.js';
// import { startSetUsers } from './actions/users';
import 'normalize.css/normalize.css';
import './styles/styles.scss';
import './firebase/firebase';
// import * as firebaseui from 'firebaseui'
//import './playground/promises';
const store = configureStore();
const jsx = (
<Provider store={store}>
<AppRouter />
</Provider>
);
ReactDOM.render(jsx, document.getElementById('app'));
My AppRouter has:
import React from 'react';
import { connect } from 'react-redux';
import { BrowserRouter, Route, Switch, Link, NavLink, withRouter } from 'react-router-dom';
import Header from '../components/Header.js';
import Footer from '../components/Footer.js';
import Dashboard from '../components/home/Dashboard.js';
import Landing from '../components/home/Landing.js';
import ErrorNotice from '../components/ErrorNotice.js';
import SignIn from '../components/auth/RegisterPage.js';
import Pending from '../components/auth/PendingPage.js';
import SignInSuccess from '../components/auth/SignInSuccess.js';
import Users from '../components/users/UserDashboard.js';
// this Higher Order Component wraps the app and listens for Firebase auth change state event
// when this state changes, it updates the store
import withAuthentication from '../hoc/withAuthentication';
import AuthenticatedRoute from '../components/auth/AuthenticatedRoute';
const AppRouter = () => {
return (
<div>
<Header />
<Switch>
<Route path="/" exact={true} component={Landing} />
{/* Authentication Related routes */}
<Route path="/Signin" component={SignIn} />
{/* This route no longer required. Was used when uiConfig has a redirect URL */}
{/* <Route path="/Loading" component={SignInSuccess} /> */}
<Route path="/Pending" component={Pending} />
{/* PUBLIC ROUTES */}
<Route path="/Users" component={Users} />
<Route path="/Menu" component={Menu} />
{/* AUTHENTICATED ROUTES */}
{/* Places routes that require authenitcation here and use the AuthenticatedRoute */}
<AuthenticatedRoute path="/Dashboard" component={Dashboard} />
<Route component={ErrorNotice} />
</Switch>
<Footer />
</div>
)
}
// set up passing of store state as component props
const mapStateToProps = state => ({
authUser: state.sessionState.authUser,
});
// connect this component to the store
// wrap withRouter to ensure that Links work: => https://reacttraining.com/react-router/core/guides/redux-integration/blocked-updates
export default withRouter(connect(mapStateToProps)(AppRouter));
Can anyone see where I'm going wrong?
revised AppRouter.js
import React from "react";
import { connect } from "react-redux";
import {
BrowserRouter,
Route,
Switch,
Link,
NavLink,
withRouter
} from "react-router-dom";
import Header from "../components/Header.js";
import Footer from "../components/Footer.js";
import Dashboard from "../components/home/Dashboard.js";
import Landing from "../components/home/Landing.js";
import ErrorNotice from "../components/ErrorNotice.js";
import SignIn from "../components/auth/RegisterPage.js";
import Pending from "../components/auth/PendingPage.js";
import SignInSuccess from "../components/auth/SignInSuccess.js";
import About from "../components/footerlinks/company/About.js";
import Users from "../components/users/UserDashboard.js";
// this Higher Order Component wraps the app and listens for Firebase auth change state event
// when this state changes, it updates the store
import withAuthentication from "../hoc/withAuthentication";
import AuthenticatedRoute from "../components/auth/AuthenticatedRoute";
const AppRouter = () => {
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path="/" exact={true} component={Landing} />
{/* Authentication Related routes */}
<Route path="/Signin" component={SignIn} />
{/* This route no longer required. Was used when uiConfig has a redirect URL */}
{/* <Route path="/Loading" component={SignInSuccess} /> */}
<Route path="/Pending" component={Pending} />
{/* PUBLIC ROUTES */}
<Route path="/About" component={About} />
<Route path="/Users" component={Users} />
<Route path="/Menu" component={Menu} />
{/* AUTHENTICATED ROUTES */}
{/* Places routes that require authenitcation here and use the AuthenticatedRoute */}
<AuthenticatedRoute path="/Dashboard" component={Dashboard} />
<Route component={ErrorNotice} />
</Switch>
<Footer />
</div>
</BrowserRouter>;
};
// set up passing of store state as component props
const mapStateToProps = state => ({
authUser: state.sessionState.authUser
});
// connect this component to the store
// wrap withRouter to ensure that Links work: => https://reacttraining.com/react-router/core/guides/redux-integration/blocked-updates
export default connect(mapStateToProps)(AppRouter);
console errors after removing withRouter from the import statement:
Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.
in Route (created by AppRouter)
in AppRouter (created by Connect(AppRouter))
in Connect(AppRouter)
in Provider
Warning: AppRouter(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
printWarning # warning.js:33
warning # warning.js:57
warnIfInvalidElement # ReactCompositeComponent.js:51
mountComponent # ReactCompositeComponent.js:193
mountComponent # ReactReconciler.js:45
performInitialMount # ReactCompositeComponent.js:370
mountComponent # ReactCompositeComponent.js:257
mountComponent # ReactReconciler.js:45
performInitialMount # ReactCompositeComponent.js:370
mountComponent # ReactCompositeComponent.js:257
mountComponent # ReactReconciler.js:45
performInitialMount # ReactCompositeComponent.js:370
mountComponent # ReactCompositeComponent.js:257
mountComponent # ReactReconciler.js:45
mountComponentIntoNode # ReactMount.js:104
perform # Transaction.js:143
batchedMountComponentIntoNode # ReactMount.js:126
perform # Transaction.js:143
batchedUpdates # ReactDefaultBatchingStrategy.js:62
batchedUpdates # ReactUpdates.js:97
_renderNewRootComponent # ReactMount.js:319
_renderSubtreeIntoContainer # ReactMount.js:401
render # ReactMount.js:422
(anonymous) # app.js:29
__webpack_require__ # bootstrap 8dde10c53183363cc06e:19
(anonymous) # bundle.js:50261
__webpack_require__ # bootstrap 8dde10c53183363cc06e:19
module.exports # bootstrap 8dde10c53183363cc06e:62
(anonymous) # bootstrap 8dde10c53183363cc06e:62
invariant.js:42 Uncaught Error: AppRouter(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object
I think the problem is that your AppRouter is not returning anything. In the arrow function if you write () => {statement} it will execute the statement but if you write () => statement it will return it. So you should modify the AppRouter to:
const AppRouter = () => (
<BrowserRouter>
...
</BrowserRouter>
);
More info about the arrow functions:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Hope it helps.
Hi #Mel I faced similar issue a few days back, and i resolved it as following:
In your index.html, check that your id is app and not root.
Modify your app.js to have:
const jsx = (
<Provider store={store}>
<BrowserRouter>
<AppRouter />
</BrowserRouter>
</Provider>
);
Now, your AppRouter needs to be a class based component, so it would become as following after modifying:
// All your imports come here
class AppRouter extends Component {
render() {
let routes = (
<Switch>
<Route path="/" exact={true} component={Landing} />
<Route path="/Signin" component={SignIn} />
<Route path="/Pending" component={Pending} />
<Route path="/Users" component={Users} />
<Route path="/Menu" component={Menu} />
<AuthenticatedRoute path="/Dashboard" component={Dashboard} />
<Route component={ErrorNotice} />
</Switch>
);
return (
<div>
<Header />
{routes}
<Footer />
</div>
);
}
}
const mapStateToProps = state => ({
authUser: state.sessionState.authUser
});
export default withRouter(connect(mapStateToProps)(AppRouter));
If you still face issues, let me know, I can share more code.
Hope it helps! Happy Coding! ;)
index.js or appRouter.js should contain this type of routes written
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import store from './redux-state.js';
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App>
<Switch>
<Route path="/" exact={true} component={Landing} />
<Route exact path="/" component={Home}/>
<Route component={Error404} />
</Switch>
</App>
</BrowserRouter>
</Provider>,
document.getElementById('appRoot'),
renderCommon
);
while in your app.js you can write following and it should work fine
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
function mapStateToProps(state) {
return {};
}
function mapDispatchToProps(dispatch) {
return {};
}
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
{this.props.children}
)
}
}
Just copy and paste the code. It will work. Message me if you have any issue
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from '../components/Header.js';
import Footer from '../components/Footer.js';
import NotFound from "../../ui/pages/notfound";
import Dashboard from '../components/home/Dashboard.js';
import Landing from '../components/home/Landing.js';
import ErrorNotice from '../components/ErrorNotice.js';
import SignIn from '../components/auth/RegisterPage.js';
import Pending from '../components/auth/PendingPage.js';
import SignInSuccess from '../components/auth/SignInSuccess.js';
import Users from '../components/users/UserDashboard.js';
// this represent ur actions
import { togglemenu } from "../../../actions/index";
import { bindActionCreators } from 'redux';
class AppRouter extends Component {
render() {
return (
<BrowserRouter>
<Header />
<div>
<Switch>
<Route path="/" exact={true} component={Landing} />
<Route path="/Signin" exact={true} component={SignIn} />
<Route path="/Pending" exact={true} component={Pending} />
{/* PUBLIC ROUTES */}
<Route path="/Users" exact={true} component={Users} />
<Route path="/Menu" exact={true} component={Menu} />
<Route component={NotFound} />
</Switch>
</div>
<Footer />
</BrowserRouter>
)
}
}
function mapStateToProps(state) {
return {
// ur redux state
home: state.home
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
// ur redux action
togglemenu: togglemenu
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(AppRouter);
I am learning redux with react and hit a mental roadblock, I have the following entry index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Redirect, Route} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store';
import Bootstrap from 'bootstrap/dist/css/bootstrap.css';
import Main from './components/front/Main';
import Login from './components/front/Login';
import Home from './components/front/Home';
import Register from './components/front/Register';
import Forgot from './components/front/Forgot';
import Verify from './components/front/Verify';
import Dashboard from './components/back/Dashboard';
import './css/app.css';
import Auth from './components/Auth';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
Auth.isLogged ? ( //<-need to get props here
<Component {...props}/>
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}}/>
)
)}/>
)
const App = () => (<BrowserRouter>
<div>
{/* PUBLIC */}
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
{/* PRIVATE */}
<PrivateRoute path="/dashboard" component={Dashboard}/>
</div>
</BrowserRouter>);
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
Overall redux works, the only problem is in this file, as I am not exporting anything, I can't get connect to work.
Ideally Auth.isLogged should be either true or false based on isAuthenticated prop, but I can't get the value passed in any way to the entry index.js
import React from 'react';
import { connect } from 'react-redux';
#connect((store) => {
return {isAuthenticated: store.auth.isAuthenticated, authenticating: store.auth.authenticating};
})
export default class Auth extends React.Component {
//Can't get anything from here to index.js
}
Please any help would be greatly appreciated!
If I understand correctly, you’re trying to provide context of store.auth.isAuthenticated to PrivateRoute.
If you declare App in its' own file you can connect it to the store and then pass the value of isAutenticated to your PrivateRoute component
//App.js
import React, { Component } from 'react'
import { withRouter, Switch, Route } from 'react-router-dom'
import { connect } from 'react-redux'
import PrivateRoute from 'components/PrivateRoute'
#withRouter
#connect(store => ({
isAuthenticated: store.auth.isAuthenticated,
authenticating: store.auth.authenticating
}))
class App extends Component {
render() {
const { isAuthenticated } = this.props
return (
<span>
{/* PUBLIC */}
{ !isAuthenticated &&
<Switch>
<Route path={'/'} exact component={Home}/>
<Route path={'/login'} component={Login}/>
<Route path={'/register'} component={Register}/>
<Route path={'/forgot'} component={Forgot}/>
<Route path={'/verify'} component={Verify}/>
</Switch>
}
{/* PRIVATE */}
{ isAuthenticated &&
<PrivateRoute
isAuthenticated={isAuthenticated}
path="/dashboard"
component={Dashboard}
/>
}
</span>
)
}
}
export default App
For readability sake you could make this change in index.js
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
)
You may or may not need to wrap connect(App) inside of withRouter, but the way I was handling my routing made this part necessary.