Learn to UseContext() with Hooks in 3 Minutes
Tags: react, javascript, codenewbie, beginners
Published: 2020-06-15 18:13:28

This is my first post on Dev.to! I'm surprised by the number of introductory React Context tutorials that use classes and `useReducer()`. I think classes and `useReducer()` overcomplicate things, so I thought I would write on `useContext()` without either.

We're going to create a super simple authentication app, and learn context in less than 3 minutes!

![Authentication app](https://media.giphy.com/media/mCDxbnTMjHJXL8w855/giphy.gif)

**Context is like a global variable - or a global Hook - that's passed to every child.** Context is a component that wraps around any other component. Every child component has access to it without being passed around through props. There are four steps to using context:

1. Initiate context
2. Provide the initiated context
3. Implement context in our app
4. Update context in our app

We're going to have an app that renders two components, one for authorized users and one for unauthorized users. This is the file structure:

- index.js
- App.js
- UserContext.js
- AuthApp.js
- UnauthApp.js

That looks like a lot! Don't worry, I also created a [CodePen](https://codepen.io/danielcurtis/pen/pogbEdz?editors=0011) with everything condensed into one file. It's 75 lines of code, including whitespace.


## Step One: Initiate Context

Initiating context is super easy. We create a variable and set it to `createContext()`. We're going to set it to a default "fallback" value. If we left it blank, it would default to an empty object, which is okay too. 

```js
const UserContext = createContext({ name: '', auth: false });
// This also works: const UserContext = createContext();
```


## Step Two: Provide Context

Creating a function to *provide* our initiated context is the most complicated part.

We're going to call a provider function with children as a prop. This function will be the parent of every other component in our app. This allows us to provide any method we create within the provider function to any other component. 
```js
const UserProvider = ({ children }) => {
  return (
    <UserContext.Provider value={{ user, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}
```
We're creating a function that provides our newly initiated context to every child component. You probably are wondering where the value prop with user, login and logout is coming from. Those are the methods that will be accessible to any child component.

Let's create them:
```js
const UserProvider = ({ children }) => {
  // User is the name of the "data" that gets stored in context
  const [user, setUser] = useState({ name: '', auth: true });

  // Login updates the user data with a name parameter
  const login = (name) => {
    setUser((user) => ({
      name: name,
      auth: true,
    }));
  };

  // Logout updates the user data to default
  const logout = () => {
    setUser((user) => ({
      name: '',
      auth: false,
    }));
  };

  return (
    <UserContext.Provider value={{ user, login, logout }}>
      {children}
    </UserContext.Provider>
  );
}
```


## Step Three: Implement Context in our App

Remember, context is a global variable. So we need to implement it as the highest level in our app, i.e. where React renders our app.

```js
import React from 'react';
import ReactDOM from 'react-dom';
import { UserProvider } from './UserContext';
import App from './App';

ReactDOM.render(
    <UserProvider>
      <App />
    </UserProvider>
  document.getElementById('root')
);
```


## Step Four: Update Context

From here on out, we're going to be **consuming** context (i.e. using and updating it). Using context just requires importing it and calling it! In `App.js`, we import it as well as authenticated and unauthenticated components. 

```js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';
import AuthApp from './AuthApp';
import UnauthApp from './UnauthApp';

function App() {
  const { user } = useContext(UserContext);

  return user.auth ? <AuthApp /> : <UnauthApp />;
}

export default App;
```

We simply import user context. Then because it's an object, we can access the auth property. Then we use a ternary operator (fancy if statement) to either return `<AuthApp />` or `<UnauthApp />`. 

`AuthApp.js` and `UnauthApp.js` similarly import the user context, and also methods to update the user context.

**`AuthApp.js`**

```js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';

function AuthApp() {
  const { user, logout } = useContext(UserContext);

  return (
    <>
      <h1>Hello, {user.name}!</h1>
      <button onClick={logout}>Logout</button>
    </>
  );
}

export default AuthApp;
```

**`UnauthApp.js`**

```js
import React, { useContext, useState } from 'react';
import { UserContext } from './UserContext';

function UnauthApp() {
  const { login } = useContext(UserContext);
  const [name, setName] = useState();

  return (
    <>
      <h1>Please, log in!</h1>

      <label>Name:</label>
      <input
        type="text"
        onChange={(event) => {
          setName(event.target.value);
        }}
      />
      <button onClick={() => login(name)}>Log in</button>
    </>
  );
}

export default UnauthApp;
```

And that's a wrap. Let me know what you think! 

A lot more goes into authentication that I did not cover. I'm currently creating a full-stack authentication example based on this post. I'll update this post with a link when it's done!

{% codepen https://codepen.io/danielcurtis/pen/pogbEdz %}