Skip to content

Instantly share code, notes, and snippets.

@dariocravero
Last active May 16, 2018 09:41
Show Gist options
  • Save dariocravero/54ef54aa7116338c28088cc89bc2197f to your computer and use it in GitHub Desktop.
Save dariocravero/54ef54aa7116338c28088cc89bc2197f to your computer and use it in GitHub Desktop.
A POC of a User/Auth context provider for React apps
import React from 'react'
const UserContext = React.createContext({})
export const Consumer = Context.Consumer
export class Provider extends React.Component {
constructor(props) {
super(props)
this.state = {
token: getToken(props.token),
login: this.login,
logout: this.logout,
data: null,
}
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.token && nextProps.token !== prevState.token) {
return {
token: nextProps.token,
data: null,
}
}
return null
}
componentDidMount() {
this.getUser()
}
componentDidUpdate() {
if (this.state.token !== prevState.token) {
this.getUser()
}
}
getUser = async () => {
if (this.state.token) {
this.setState({ data: await getUser(this.state.token) })
}
}
login = async ({ user, password }) => {
// do login stuff
const token = await login({ user, password })
if (token) {
this.setState({
token,
})
}
}
logout = () => {
// clear token
logout()
this.setState({ token: null, data: null })
}
render() {
return (
<UserContext.Provider value={this.state}>
{props.children}
</UserContext.Provider>
)
}
}
// ... at point of use ...
import * as User from './User.js'
const UserName = props => (
<User.Consumer>{user => <div>{user.data.name}</div>}</User.Consumer>
)
const LoginOrLogout = props => (
<User.Consumer>
{user =>
user.token ? (
<div onClick={user.logout}>logout</div>
) : (
<div onClick={user.login}>login</div>
)
}
</User.Consumer>
)
// ... somewhere before all the stuff above is used ...
import * as User from './User.js'
const App = props => (
<User.Provider>
<UserName /> <LoginOrLogout />{' '}
</User.Provider>
)
@dariocravero
Copy link
Author

Nested users?

const App = (
  <User.Provider>
    <User.Consumer>
      {user => (
        <React.Fragment>
          <div>this is the "main" user</div>

          <User.Provider token="magic">
            <User.Consumer>
              {user => <div>this is the magical user</div>}
            </User.Consumer>
          </User.Provider>
        </React.Fragment>
      )}
    </User.Consumer>
  </User.Provider>
)

@dariocravero
Copy link
Author

[brain dump from an internal conversation]

What happens if a part of the app needs the user but not the environment?

What happens if, say, your app stops using the environment altogether, how do you know when you can delete that loader?

In that solution, the state is held in a global store. Say you want to have a part of the app that works as if it were another user (which is a use case in Ed). How do you get to work under a different environment or impersonate a user?

In the contextual user API from above you could do something like the nested users above.
Any consumer of the app will use the second user in that subset of the app down below.

Another aspect of it is, what happens to your user if you decide to stop using sagas or redux?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment