optimizely / nuclear-js

Reactive Flux built with ImmutableJS data structures. Framework agnostic.
https://optimizely.github.io/nuclear-js/
MIT License
2.23k stars 141 forks source link

Discussion: Authentication followed by API request -- share your strategies #162

Closed auser closed 9 years ago

auser commented 9 years ago

More of a discussion than an issue, but I'm interested in knowing how or if nuclear can help solve an authentication issue. After spending way too much time trying to force my way into it, I'd thought I'd pose it here (or perhaps slack is better?).

In any case, I have a react-native app setup with an App Component that handles routing using the Navigator. Based upon the state of the app, the view that fills in is either the <LoginView /> or the app contents. Originally, I had an auth module that handles keeping track of the user/authentication status. I had to modify this to use a weird, hacky solution with promises due to the fact that after I fire an AUTH message around the app, the <App /> component rerenders which causes the authStore handler to think that the message has not yet completed as the first component fires an API request when it appears.Thus, there is a pending action while the API request goes out and nothing completes.

Any thoughts on how to get around this or perhaps share some strategies about combining auth with nuclear?

jordangarcia commented 9 years ago

Hey Ari,

This type of problem would generally be solved by using Nuclear in a reactive fashion.

To me it sounds like there are three states for your application on bootstrap, LOADING SIGNED_IN SIGNED_OUT. For sake of explanation I'll refer to it as appLoadState

In your main App component you would want to have a getter that points to the appLoadState and renders one of three things, either the loading component, a sign in component or the rest of the app.

There are several different ways to represent this state within a Nuclear system.

One way is you have an Auth module that has a store that tracks isSignedIn. The same store could also track hasLoaded state of whether or not authentication is complete. Given these two pieces of state we can combine -> reduce them into the single piece of appLoadState

Example Code:

auth/getters.js

exports.appLoadState = [
  ['auth', 'hasLoaded'],
  ['auth', 'isSignedIn'],
  (hasLoaded, isSignedIn) => {
    if (!hasLoaded) {
     return 'LOADING';
    }
    return (isSignedIn)
      ? 'SIGNED_IN'
      : 'SIGNED_OUT'
    }
];

In your app component:

module.exports = React.createClass({
  mixins: [reactor.ReactMixin],

  getDataBindings() {
    return {
      appLoadState: Auth.getters.appLoadState
    }
  },

  componentWillMount() {
    Auth.actions.authenticate();
  },

  render() {
    switch (this.state.appLoadState) {
    case 'LOADING':
      return <LoadingComponent />
    case 'SIGNED_IN':
      return <SignedInAppComponent />      
    case 'SIGNED_OUT':
      return <LoginComponent />      
  }
});

Hope this helps!

auser commented 9 years ago

Ah, I dig the reducer step there.

I have something very similar set up, but the difference is that I've combined the app state and the navigator in the same view in the same view so the event doesn't complete until the Navigator component finishes rendering, which is what causes the problem. Separating the components into two different pieces (as you suggest) would solve that problem.

Thanks for the suggestion. Loving nuclear, btw.