Mini Guide to passing around data in React
Published: 2022-01-05 10:17:38

When I was learning React, I had to learn Redux and how to avoid prop drilling. It was really painful just to pass around data from hooks to the children. I just went through a 2 years old repo and was shocked to find massive unnecessary lines of code, updated the repo and I thought to write about it.

In this article, we are going to simplify how to pass props (data) around your application using createContext and useContext. 
There are three steps:
1. Create the Context.
2. Provide the context for others to use.
3. use the context.
 
Okay, let's get to it.

## 1. Create The Context.
Assuming your use case is authentication and you are using Google Firebase, you would definitely want to know at all times if a user is authenticated, or the user has verified their email or getting the UID of the the user for API calls, you can store the user's data in a context and make it available anywhere in your application with the help of createContext.

```
import React, { createContext } from "react";
import { put firebase imports here} from "firebase/auth";

const app = initializeApp(...)
const auth = getAuth(app);

## Let create the context
export const authContext = createContext();

```

I named the context "authContext" but you can name it anything you want.
Next, we need to:
## 2. Provide The Context to others.
After creating the context, we have access to a method call `Provider` which, you guessed it, provides the context to the children of the component. 

**_Side Note: A child is any code inside the return method._**

There are two sub-steps to provide our context for other components.

2.1. Create the provider component
2.2. Wrap the entire app with the provider (so that the whole app becomes a child of the provider, and gets to benefit from all it provides, haha pun definitely intended).

```
##2.1. Create the provider component
##Since it provides Auth-entication, let's call it AuthProvider

export const AuthProvider = ({children}) => {

    const [currentUser, setCurrentUser] = useState(null)
    const [loading, setLoading] = useState(true)

    useEffect(() => {
        onAuthStateChanged(auth, (user) => {
            setCurrentUser(user);
            setLoading(false);
        });
          
    }, [])

    return (
        <authContext.Provider value={currentUser}>
            {!loading && children}
        </authContext.Provider>
    )
}

##2.2. Wrap the entire app with the provider

const App = () =>{
  return (
    <AuthProvider>
      <ProtectedComponent />
    </AuthProvider>
  );
}
```
I won't go into details because this is not a tutorial about firebase but as you can see, we used firebase `onAuthStateChanged` method to get the user's data and store it in a variable called `currentUser`, which we then passed as the value in the Provider 

```
<authContext.Provider value={currentUser}>
```
##3. Use The Context
Now that the context is ready for consumption, to use it in another component, we simply import useContext plus our authContext we create in step 1 to get `currentUser` data anywhere.

```
import React, { useContext } from "react";
import { authContext } from "firebase/Config.js";

const { currentUser } = useContext(authContext)
```

I used mine in a `PrivateRoute` component but now that you have access to the `currentUser` anywhere, use it as you will. Here's how I used it.

```

export const PrivateRoute = ({ component, ...rest }) => {
  const { currentUser } = useContext(authContext)
 
  return (
    <Route {...rest} render={routeProps => {
      return currentUser ? (
        renderMergedProps(component, routeProps, rest)
      ) : (
        <Redirect to={{
          pathname: "/login",
          state: { from: routeProps.location }
        }}/>
      );
    }}/>
  );
};
```
The PrivateRoute component checks if the user is logged in (`currentUser is not null`) and give them access, if they are not logged in (`currentUser is null`), takes them to the login page. Simple!

##Caveats of context API
Beware that React context (createContext and useContext) rerenders its children every time the props change, which, if you cannot tell, can be a very bad behavior. But in the case of authentication, that's exactly what we want, that's why I made it a global wrap. So only wrap your context around components which needs to rerender when the context props change. better yet, consider using [component composition](https://reactjs.org/docs/composition-vs-inheritance.html) if the props you want to pass around are not global variables.

But! If you didn't wrap your context around the entire app, you may run into errors when you want to reuse a wrapped component outside the scope of the context. Oh no! You shall not pass! You cannot do that. This is super difficult to debug if you are not familiar with the limitation. You simply cannot use a component inside a context and reuse it outside of the context scope.

##Conclusion
Voila! Your mini guide to passing around data within your React application. If you want to see the full implementation with firebase source code, let me know down in comments.