guide
                                
                                 guide copied to clipboard
                                
                                    guide copied to clipboard
                            
                            
                            
                        Get rid of withAuth?
Made withAuth to not have to mess with <App> and give example of making HOC. Not feeling like either reason is very important.
Globals?
Inspired by DHH's series on writing software well, in an episode recommending judicious use of globals, eg for the current user.
Could be used for login/logout functions.
- Pro: Easy
- Con: Testing—for various forms of testing (including explicit unit tests and things like storybook), you then have to mock out the globals.
// CurrentUserQuery.js
export let login, logout
class CurrentUserQuery extends Component
  constructor() {
    login = this.login
    logout = this.logout      
  }
  login = () => 
  logout = () => 
So that eg in Profile.js you can:
import { login, logout } from './CurrentUserQuery'
instead of getting them as props.
Prop drilling vs HOC vs Context/unstated
Need a reactive data source for loading & currentUser, so can't do globals.
Reusable query
Could do a withUser() HOC that provides them through graphql() to any component that needs it. All using default cache-first, and deduplication should combine them into one query, while also maintaining data.loading/loadingUser.
- Pro: concise. Using Apollo store like the global variable it is
- Con: how to incorporate loggingInintoloading? In the single-usewithAuth, it's defined as:loading={loading || this.state.loggingIn}
class Profile extends Component {
  ...
}
export default withUser(Profile)
(or alternatively could make a reusable <WithUser> query component, but that takes more characters and indentation to use)
Prop drilling
A single normal query at the top. Lot of drilling. It's nice for testing, but not nice to read/write. Would personally prefer to avoid.
<CurrentUserQuery>
  {({ loading, error, data }) => (
    <App loadingUser={loading} currentUser={data.currentUser} />
  )}
</CurrentUserQuery>
Context/unstated
- Pro: no drilling
- Con: verbose
Hey @lorensr IMO, if you are using withAuth once, why make it at all? I'd rather not allow it to exist.
One authentication service, like Auth.js with all the helpers needed can do the magic. Check this Auth Service file.
And then comfortably bring in the withUser HOC!
Thanks—do you see any downsides to reusing withUser everywhere instead of using it once at the top and prop drilling?
On Sun, Jun 17, 2018 at 6:28 AM Prosper Otemuyiwa [email protected] wrote:
Hey @lorensr https://github.com/lorensr IMO, if you are using withAuth once, why make it at all? The withAuth might really not need to exist.
One authentication service, like Auth.js with all the helpers needed can do the magic. Check this Auth Service file https://github.com/auth0/blog/blob/master/_includes/asides/react.markdown#dependencies-and-setup. And tie it in with the withUser HOC
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/GraphQLGuide/guide/issues/33#issuecomment-397869396, or mute the thread https://github.com/notifications/unsubscribe-auth/AAPVmKnVE2P2gn00mn08vMhORkDsQ1tOks5t9i80gaJpZM4Uh7y5 .
No, I don't. It's just a matter of trade-offs.
Do you want to prevent prop drilling because of how stressful and confusing it can be in the long run? If yes, then just use the withUser HOC anywhere you need it.
Okay, here's the plan! I'm liking it a lot. Lmk if you have any further thoughts @unicodeveloper @jeresig
- direct user query
- login/logout: globals
- loginInProcessstatus: apollo-link-state
- withUser: cache-only HOC
// withUser.js
export const USER_QUERY = gql`
  query UserQuery {
    currentUser {
      firstName
      name
      username
      email
      photo
      hasPurchased
    }
    loginInProcess @client
  }
`
export const withUser = graphql(USER_QUERY, {
  options: { fetchPolicy: 'cache-only' },
  props: ({ data: { currentUser, loginInProcess, loading } }) => ({
    user: currentUser,
    loggingIn: loginInProcess || loading
  })
})
// auth.js
const fetchUserData = () =>
  apollo.query({
    query: USER_QUERY,
    fetchPolicy: 'network-only'
  })
// fetch at pageload in case client is already logged in
fetchUserData()
export const login = () => {
  apollo.writeData({ data: { loginInProcess: true } })
  auth0Login({
    onCompleted: e => {
      apollo.writeData({ data: { loginInProcess: false } })
      if (e) {
        console.error(e)
        return
      }
      apollo.reFetchObservableQueries()
      fetchUserData()
    }
  })
}
export const logout = () => {
  auth0Logout()
  apollo.resetStore()
}
And then in components:
import { withUser } from '../lib/withUser'
import { login, logout } from '../lib/auth'
class Profile extends Component
…
export default withUser(Profile)
This simplifies App.js/routing a lot and completely eliminates passing around login/logout/user/loggingIn everywhere.
Turned out to be simpler—given deduplication and default cache-first fetch policy, there's no point to the fetchUserData and fetchPolicy: 'cache-only'