Coder Social home page Coder Social logo

Comments (14)

mjrussell avatar mjrussell commented on August 11, 2024 11

@katcu
The issue is in how the code split route loading is set up with the boilerplate. I haven't used System.import much but you need to move the application of the wrapper to the loadModule function instead of inside the renderRoute.

If you want to apply the wrapper HOC in the routes file you can do the following:

edit: There can be some unnecessary mount/unmounting when applying HOCs inside getComponent because each time the route is rendered, a new component is returned from the HOC. See #44 for details. This can result in poor performance/subtle bugs. Instead scroll down to see how to apply the HOC inside the Component file

// These are the pages you can go to.
// They are all wrapped in the App component, which should contain the navbar etc
// See http://blog.mxstbr.com/2016/01/react-apps-with-pages for more information
// about the code splitting business
import { getHooks } from './utils/hooks';
import { routerActions } from 'react-router-redux'
import { UserAuthWrapper } from 'redux-auth-wrapper'

const errorLoading = (err) => {
  console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
};

const loadModule = (cb, hoc) => (componentModule) => {
  if (hoc) {
    cb(null, hoc(componentModule.default));
  } else {
    cb(null, componentModule.default);
  }
};

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => null,
  predicate: authData=>false,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
});


export default function createRoutes(store) {
  // create reusable async injectors using getHooks factory
  const { injectReducer, injectSagas } = getHooks(store);

  return [
    {
      path: '/',
      name: 'home',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          System.import('containers/HomePage/reducer'),
          System.import('containers/HomePage/sagas'),
          System.import('containers/HomePage'),
        ]);

        const renderRoute = loadModule(cb, UserIsAuthenticated);

        importModules.then(([reducer, sagas, component]) => {
          injectReducer('home', reducer.default);
          injectSagas(sagas.default);
          renderRoute(component);
        });

        importModules.catch(errorLoading);
      },
    }, {
      path: '/features',
      name: 'features',
      getComponent(nextState, cb) {
        System.import('containers/FeaturePage')
          .then(loadModule(cb))
          .catch(errorLoading);
      },
    }, {
      path: '*',
      name: 'notfound',
      getComponent(nextState, cb) {
        System.import('containers/NotFoundPage')
          .then(loadModule(cb))
          .catch(errorLoading);
      },
    },
  ];
}

Alternatively, you could move the user wrapper into the component definition

Using decorators: (assuming you add the transform-decorators-legacy to your babel plugins)

@UserIsAuthenticated
export class HomePage extends React.Component {
...

Or just regular HOC application:

...
// Wrap the component to inject dispatch and state into it
export default UserIsAuthenticated(connect(createSelector(
  selectRepos(),
  selectUsername(),
  selectLoading(),
  selectError(),
  (repos, username, loading, error) => ({ repos, username, loading, error })
), mapDispatchToProps)(HomePage));

from redux-auth-wrapper.

katcu avatar katcu commented on August 11, 2024 2

@mjrussell Thank you for looking into this. The way that use System.import to import components led to the issue. and as you said, it's difficult integrating it with other NICE modules. I've just changed to a similar boilerplate, issues resolved and everything works as expected.
Thanks again for the nice clean wrapper 👍

from redux-auth-wrapper.

katcu avatar katcu commented on August 11, 2024 1

@mjrussell
I simply did the follow steps, then visit http://localhost:3000/features . it should redirect me to /login, right?

Clone this repo using$ git clone --depth=1 https://github.com/mxstbr/react-boilerplate.git
Run $ npm run setupto install dependencies and clean the git repo.
At this point you can run $ npm startto see the example app at http://localhost:3000.

npm install --save redux-auth-wrapper

change the /app/routes.js code as following:

// These are the pages you can go to.
// They are all wrapped in the App component, which should contain the navbar etc
// See http://blog.mxstbr.com/2016/01/react-apps-with-pages for more information
// about the code splitting business
import { getHooks } from './utils/hooks';
import { routerActions } from 'react-router-redux'
import { UserAuthWrapper } from 'redux-auth-wrapper'

const errorLoading = (err) => {
  console.error('Dynamic page loading failed', err); // eslint-disable-line no-console
};

const loadModule = (cb) => (componentModule) => {
  cb(null, componentModule.default);
};

const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => null,
  //authSelector: null,
  predicate: authData=>false,
  redirectAction: routerActions.replace,
  wrapperDisplayName: 'UserIsAuthenticated'
})

export default function createRoutes(store) {
  // create reusable async injectors using getHooks factory
  const { injectReducer, injectSagas } = getHooks(store);

  return [
    {
      path: '/',
      name: 'home',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          System.import('containers/HomePage/reducer'),
          System.import('containers/HomePage/sagas'),
          System.import('containers/HomePage'),
        ]);

        const renderRoute = loadModule(cb);

        importModules.then(([reducer, sagas, component]) => {
          injectReducer('home', reducer.default);
          injectSagas(sagas.default);

          renderRoute(UserIsAuthenticated(component));
        });

        importModules.catch(errorLoading);
      },
    }, {
      path: '/features',
      name: 'features',
      getComponent(nextState, cb) {
        System.import('containers/FeaturePage')
          .then(loadModule(cb))
          .catch(errorLoading);
      },
    }, {
      path: '*',
      name: 'notfound',
      getComponent(nextState, cb) {
        System.import('containers/NotFoundPage')
          .then(loadModule(cb))
          .catch(errorLoading);
      },
    },
  ];
}

from redux-auth-wrapper.

chaintng avatar chaintng commented on August 11, 2024 1

@mjrussell your approach work like magic!
Thank you so much!

from redux-auth-wrapper.

mjrussell avatar mjrussell commented on August 11, 2024

@katcu do you have a branch you are trying this on that I could look at? I haven't used that boilerplate but it should integrate cleanly

from redux-auth-wrapper.

katcu avatar katcu commented on August 11, 2024

hold on pls... @mjrussell

from redux-auth-wrapper.

katcu avatar katcu commented on August 11, 2024

Hi, pls check out my branch of issue repoduction https://github.com/katcu/redux-form-with-react-boilerplate/tree/redux-auth-wrapper-with-react-boilerplate

from redux-auth-wrapper.

mjrussell avatar mjrussell commented on August 11, 2024

@katcu thanks Im going to look into this today

from redux-auth-wrapper.

hurkanyakay avatar hurkanyakay commented on August 11, 2024

Recently solved this problem thanks to this issue. I noticed this important warning in main page that:

If you are using getComponent in React Router you should not apply the auth-wrapper inside getComponent. This will cause React Router to create a new component each time the route changes.

I guess we can't use
const loadModule = (cb, hoc) => (componentModule) => {
approach.

from redux-auth-wrapper.

mjrussell avatar mjrussell commented on August 11, 2024

@hurkanyakay Yeah good point. We realized afterwards that the loadModule approach can have some weird edge cases. See #44 for more details. That issue prompted the warning in the README but I never came back to this issue. Im going to edit my original suggestion to encourage using the HOC in the component file.

from redux-auth-wrapper.

JustinJKlein avatar JustinJKlein commented on August 11, 2024

Hi all,
I am still a bit lost on the best way to go about getting this setup to work with my project built with the react-boilerplate. I want/need to run this as a hoc but it is not apparent to me what I need to get it other than my export for the component I want to wrap needs to be altered in the manner provided mjrussel above. But, I do not know what imports are needed or where to define my const for UserIsAuthenticated because they are not in the example for hoc. I know I am likely missing something simple so I apologize in advance if its a no brainer.

from redux-auth-wrapper.

mjrussell avatar mjrussell commented on August 11, 2024

@JustinJKlein it is up to you to decide where you want to define your HOC wrappers. I see many examples (and my own projects) create a file authWrappers.js in which you define the HOC and then they import it either into their Route definition file or their Component definition file. Because you are using react-boilterplate with System.import, you need to apply them inside the Component definition file.

So it might look something like:
authWrappers.js

import { UserAuthWrapper } from 'redux-auth-wrapper'

// Redirects to /login by default
export const UserIsAuthenticated = UserAuthWrapper({
  authSelector: state => state.user, // how to get the user state
  redirectAction: routerActions.replace, // the redux action to dispatch for redirect
  wrapperDisplayName: 'UserIsAuthenticated' // a nice name for this auth check
});

MyComponent.js

import React, { Component } from 'react';

import { UserIsAuthenticated } from './authWrappers';

class MyComponent extends Component {
  render() {
    return <h1>Renders a thing</h1>;
  }
}

export default UserIsAuthenticate(MyComponent);

from redux-auth-wrapper.

LearningDave avatar LearningDave commented on August 11, 2024

Hi there,

im currently trying to add auth to my navigation bar (based react-boilerplate). After some help from @mjrussell yesterday, i could make it work for containers generelly (thanks mate :) )

However now i want to use this approach (readme code example):

// Admin Authorization, redirects non-admins to /app and don't send a redirect param
const UserIsAdmin = UserAuthWrapper({
  authSelector: state => state.user,
  redirectAction: routerActions.replace,
  failureRedirectPath: '/app',
  wrapperDisplayName: 'UserIsAdmin',
  predicate: user => user.isAdmin,
  allowRedirectBack: false
})

// Now to secure the component: first check if the user is authenticated, and then check if the user is an admin
<Route path="foo" component={UserIsAuthenticated(UserIsAdmin(Admin))}/>

My Header(navigation) container looks like this:

class Header extends React.Component { // eslint-disable-line react/prefer-stateless-function
  render() {
      return (
        <div>
          <NavBar>
            <HeaderLink to="/front">
              <FormattedMessage {...messages.front} />
            </HeaderLink>
            <HeaderLink to="/admin">
              <FormattedMessage {...messages.admin} />
            </HeaderLink>
            <Button onClick={this.props.onClickLogout}>
              <FormattedMessage {...messages.logout} />
            </Button>
          </NavBar>
        </div>
      );
  }
}

I would like to enable/disable HeaderLinks Component using a authWrapper.
Could you please help me out to find a fitting solution?

Thanks in advance! :)

from redux-auth-wrapper.

mjrussell avatar mjrussell commented on August 11, 2024

@LearningDave please see the section in the Readme on Hiding and Alternate Components which is I think what you are asking. You dont want the redirection in this case

from redux-auth-wrapper.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.