redux-token-auth icon indicating copy to clipboard operation
redux-token-auth copied to clipboard

I am receiving weird error regarding GatePage.

Open suyesh opened this issue 6 years ago • 8 comments

Error

Could not find "store" in either the context or props of "Connect(GatedPage)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(GatedPage)".

Main index

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import "./assets/css/main.scss";
import App from "./App";
import { configureStore } from "./store";
import { verifyCredentials } from "./lib";
import * as serviceWorker from "./utils/serviceWorker";

const store = configureStore();
verifyCredentials(store);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById("root")
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

Routes

import React, { Component, Fragment } from "react";
import { Route } from "react-router-dom";
import { generateRequireSignInWrapper } from "redux-token-auth";

import { Home, Login, Protected, SignUp } from "../containers";
import {
  ROOT_PATH,
  SIGN_IN_PATH,
  SIGN_UP_PATH,
  PROTECTED_PATH
} from "../constants/routes";

const requireSignIn = generateRequireSignInWrapper({
  redirectPathIfNotSignedIn: "/login"
});

export default class Routes extends Component {
  render() {
    return (
      <Fragment>
        <Route exact path={ROOT_PATH} component={Home} />
        <Route path={PROTECTED_PATH} component={requireSignIn(Protected)} />
        <Route path={SIGN_IN_PATH} component={Login} />
        <Route path={SIGN_UP_PATH} component={SignUp} />
      </Fragment>
    );
  }
}

Main App container

import React, { Component } from "react";

import { withHead } from "../lib";
import { Layout } from "../components";
import Routes from "../Routes";

class App extends Component {
  render() {
    return (
      <Layout>
        <Routes />
      </Layout>
    );
  }
}

export default withHead(App);

Versions

  "dependencies": {
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-redux": "^6.0.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.2",
    "redux": "^4.0.1",
    "redux-thunk": "^2.3.0",
    "redux-token-auth": "^0.19.0",
  }

suyesh avatar Dec 26 '18 18:12 suyesh

+1

antonwestman avatar Jan 28 '19 21:01 antonwestman

I have the same problem. :/

allefgomes avatar Apr 14 '19 15:04 allefgomes

I have the same problem. :/

I couldn't find a solution so ended up developing my own PrivateRoutes setup. Not perfect but does the job. See below my code if that helps.

import React from 'react';
import {Route, Redirect} from 'react-router-dom'

export default function PrivateRoute({ component: Component, authed, ...rest }) {
    return (
        <Route
            {...rest}
            render={props =>
                authed === true ? (
                    <Component {...props} />
                ) : (
                    <Redirect
                        to={{
                            pathname: "/login",
                            state: { from: props.location }
                        }}
                    />
                )
            }
        />
      );
    }
import React, {Component} from 'react';
import {Route} from 'react-router-dom'
import { connect } from 'react-redux'
import {withRouter} from 'react-router-dom';
import PrivateRoute from './PrivateRoute'
import Home from './components/Home.js'
import Profile from './components/Users/Profile.js'
import Logout from './components/Users/Logout.js'

class Routes extends Component {
    constructor(props){
        super(props)
        this.state={
            auth: this.props.isSignedIn
        }
    }
    componentDidUpdate(prevProps){
        if(this.props.isSignedIn !== prevProps.isSignedIn){
          this.setState({
              auth: this.props.isSignedIn
          })
        }
      }

    render(){
            return(
                <React.Fragment>
                    <Route exact path="/" component={Home} />
                    <PrivateRoute authed={this.state.auth} exact path="/profile" component={Profile} />
                    <PrivateRoute authed={this.state.auth} exact path="/logout" component={Logout} />
                </React.Fragment>
            )
    }
}

function mapStateToProps (state) {
    return {
        isSignedIn: state.reduxTokenAuth.currentUser.isSignedIn
    }
  }
  
  export default withRouter(connect(mapStateToProps, null)(Routes));

Bechev avatar Apr 14 '19 16:04 Bechev

I have the same problem. :/

I couldn't find a solution so ended up developing my own PrivateRoutes setup. Not perfect but does the job. See below my code if that helps.

import React from 'react';
import {Route, Redirect} from 'react-router-dom'

export default function PrivateRoute({ component: Component, authed, ...rest }) {
    return (
        <Route
            {...rest}
            render={props =>
                authed === true ? (
                    <Component {...props} />
                ) : (
                    <Redirect
                        to={{
                            pathname: "/login",
                            state: { from: props.location }
                        }}
                    />
                )
            }
        />
      );
    }
import React, {Component} from 'react';
import {Route} from 'react-router-dom'
import { connect } from 'react-redux'
import {withRouter} from 'react-router-dom';
import PrivateRoute from './PrivateRoute'
import Home from './components/Home.js'
import Profile from './components/Users/Profile.js'
import Logout from './components/Users/Logout.js'

class Routes extends Component {
    constructor(props){
        super(props)
        this.state={
            auth: this.props.isSignedIn
        }
    }
    componentDidUpdate(prevProps){
        if(this.props.isSignedIn !== prevProps.isSignedIn){
          this.setState({
              auth: this.props.isSignedIn
          })
        }
      }

    render(){
            return(
                <React.Fragment>
                    <Route exact path="/" component={Home} />
                    <PrivateRoute authed={this.state.auth} exact path="/profile" component={Profile} />
                    <PrivateRoute authed={this.state.auth} exact path="/logout" component={Logout} />
                </React.Fragment>
            )
    }
}

function mapStateToProps (state) {
    return {
        isSignedIn: state.reduxTokenAuth.currentUser.isSignedIn
    }
  }
  
  export default withRouter(connect(mapStateToProps, null)(Routes));

Thanks.

allefgomes avatar Apr 15 '19 20:04 allefgomes

you can also just replace the requireSignIn function by this one:

import React, { useEffect } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'

const LOGIN_PATH = '/login'

[...]

const requireSignIn = Component =>
  compose(
    withRouter,
    connect(state => ({ authUser: state.reduxTokenAuth.currentUser })),
  )(({ authUser, ...props }) => {
    useEffect(() => {
      if (!authUser.isSignedIn && !authUser.isLoading) props.history.push(LOGIN_PATH)
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [authUser])
    return authUser ? <Component {...props} /> : null
  })

gtournie avatar May 20 '19 23:05 gtournie

When using @gtournie solution I found again the race condition of redux-token-auth and react-router that redirected me to GatePage soon before token had been verified. So I decided to stick again to generateRequireSignInWrapper

#35

Briefly, the problem is related to react-redux version 6 which creates a separated context, then the GatePage component under this library cannot reach to store, even though Provider is corrected setup

https://github.com/reduxjs/react-redux/issues/1166#issuecomment-460204182

The problem can be solved if the context is matched, so upgrading react-redux and its dependencies to match to your main app package.json can simply fix.

It should be mentioned in the docs. Personally I decide to fork instead of making PR since the author has been inactive

keymastervn avatar Sep 11 '19 09:09 keymastervn

@suyesh Follow https://yarnpkg.com/lang/en/docs/selective-version-resolutions/, Adding this config to your package.json to resolve the issue, I tested and it works

  "resolutions": {
    "react-redux": "^7.1.1"
  },

This config tells redux-token-auth depends on newest react-redux version

tropicalwhite avatar Oct 08 '19 02:10 tropicalwhite

React Router (react-router-dom) 5.x works with history 4.x. If redirects not working properly or not rendering, downgrade histroy version.

mawais786 avatar Nov 26 '21 14:11 mawais786