DEV Community

Karl Castillo
Karl Castillo

Posted on

React: Simple Auth Flow

Now that we know how to use useState, useReducer and Context, how can we put these concepts into our projects? An easy example is to create a simple authentication flow.

We'll first setup the UserContext using React Context.

import { createContext } from 'react'

const UserContext = createContext({
  user: null,
  hasLoginError: false,
  login: () => null,
  logout: () => null
})

export default UserContext
Enter fullscreen mode Exit fullscreen mode

Now that we've created a context, we can start using it in our wrapping component. We'll also use useReducer to keep the state of our context.

import UserContext from './UserContext'

const INITIAL_STATE = {
  user: null,
  hasLoginError: false
}

const reducer = (state, action) => { ... }

const App = () => {
  const [state, dispatch] = useReducer(reducer, INITIAL_STATE)

  return (
    <UserContext.Provider>
      ...
    </UserContext.Provider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Our reducer will handle 2 action types -- login and logout.

const reducer = (state, action) => {
  switch(action.type) {
    case 'login': {
      const { username, password } = action.payload
      if (validateCredentials(username, password)) {
        return {
          ...state,
          hasLoginError: false,
          user: {} // assign user here
        }
      }

      return {
        ...state,
        hasLoginError: true,
        user: null
      }
    }
    case 'logout':
      return {
        ...state,
        user: null
      }
    default:
      throw new Error(`Invalid action type: ${action.type}`)
  }
}
Enter fullscreen mode Exit fullscreen mode

After implementing the reducer, we can use dispatch to call these actions. We'll create functions that we'll pass to our provider's value.

...
const login = (username, password) => {
  dispatch({ type: 'login', payload: { username, password } })
}
const logout = () => {
  dispatch({ type: 'logout' })
}

const value = {
  user: state.user,
  hasLoginError: state.hasLoginError,
  login,
  logout
}

return (
  <UserContext.Provider value={value}>
    ...
  </UserContext.Provider>
)
Enter fullscreen mode Exit fullscreen mode

Now that our value gets updated when our state updates, and we passed the login and logout function; we'll have access to those values in our subsequent child components.

We'll make two components -- LoginForm and UserProfile. We'll render the form when there's no user and the profile when a user is logged in.

...
<UserContext.Provider value={value}>
  {user && <UserProfile />}
  {!user && <LoginForm />}
</UserContext.Provider>
...
Enter fullscreen mode Exit fullscreen mode

Let's start with the login form, we'll use useState to manage our form's state. We'll also grab the context so we have access to login and hasLoginError.

const { login, hasLoginError } = useContext(UserContext)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')

const onUsernameChange = evt => setUsername(evt.target.value)
const onPasswordChange = evt => setPassword(evt.target.value)
const onSubmit = (evt) => {
  evt.preventDefault()
  login(username, password)
}

return (
  <form onSubmit={onSubmit}>
    ...
    {hasLoginError && <p>Error Logging In</p>}
    <input type='text' onChange={onUsernameChange} />
    <input type='password' onChange={onPasswordChange} />
    ...
  </form>
)
Enter fullscreen mode Exit fullscreen mode

If we're logged in we need access to the user object and the logout function.

const { logout, user } = useContext(UserContext)

return (
  <>
    <h1>Welcome {user.username}</h1>
    <button onClick={logout}>Logout</button>
  </>
)
Enter fullscreen mode Exit fullscreen mode

Now, you have a simple authentication flow in React using different ways we can manage our state!

Code Sandbox

Top comments (5)

Collapse
 
codeizm profile image
Codeizm

Great work..

Collapse
 
koralarts profile image
Karl Castillo

Thanks!

Collapse
 
codeizm profile image
Codeizm

Karl.U welcome. I have a some problems. Can u help me ? Thanks.

Collapse
 
monfernape profile image
Usman Khalil

Where do I get dispatch from while calling action? Sorry for the dumb question, I'm coming from redux.

Collapse
 
koralarts profile image
Karl Castillo

The dispatch is coming from useReducer. You can check out this post for more info about useReducer.