Hello useContext!
Published: 2023-11-09 05:41:13

**W**hen first introduced to the world of React we tend to make our executions more complex than they need to be. Don't get me wrong, after only a year of studying software engineering my executions at times are more complex than needed. But isn't that the beauty of creating and building out code? Those aha moments?! I had a particular aha moment in the last application I built. It allowed me to realize why hooks can benefit the building process on the frontend of an application. This particular hook I'm speaking of is called **_useContext_**.

**u**seContext allows us to share data between components without having to pass that data from a parent component to a child component to another child and so on. The process of passing data like so, is called **_prop drilling_**.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/my7m1mjmn0ry95yq3ihg.jpeg)

**A**bove we have a parent component _MoviePage_. You can see that I have set a variable _selectedMovie_ with a value of a movie in the database based on a condition. I know I'm going to need this data for this parent's child, _ReviewCard_. The reasoning behind this is when a review is deleted I can update the selected movie, its reviews, and set a new state for my movie's array and its relations. In my  _ReviewCard_ import I pass a prop called _selectedMovie_ equal to our variable _selectedMovie_. This allows me to use the data from the parent in the _ReviewCard_ child component. I recommend keeping the prop naming conventions the same as the data variable or function names you are passing. As your app grows there's a good chance of easily getting confused with the data you're working with. Doing this will save you time from having to go back and forth between components to remind you of what's actually in front of you. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gn7h47fzuonp45twvl9x.jpeg)

**I**n our _ReviewCard_ child component we are destructuring our _selectedMovie_ prop. **Don't forget to destruct your props!** I can't tell you how many times I've forgotten this one small detail and spent hours wondering why my execution wouldn't work. Now I'm able to use the data needed to update the selected movie, its reviews, and set a new state for my movie's array and its relations once a review is deleted. But is this truly considered prop drilling? Remember _prop drilling is having to pass data from a parent component to a child component to another child and so on._ For this to be considered prop drilling, imagine that the _ReviewCard_ component has a child. This child was the actual component that needed the data from the _MoviePage_ component, which is the parent of _ReviewCard_. We pass our prop from _MoviePage_ to _ReviewCard_ and pass the prop to this component's child. Ladies, gents, thems and theys... that is prop drilling at it's finest.

**A**lthough prop drilling isn't completely frowned upon, _useContext_ can be used globally throughout your application and prevents the action of having to prop drill. A bonus that comes along with this hook is that it will make it easier to keep track of data you want to share with other components and calls for cleaner code. In my application, I have four models set up in the backend. _User, Movie, Review, and Reply_. On the frontend, all of them will have their state set up for the data they retain. Now I could technically create one _provider component_ where I would create context for all models and set state for data like I did in a project when I first learned _useContext_: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7lwpn3xt0p6ynh09jzl.jpeg)

As you can see, given the _useState()_ setup, I was using one _provider component_ to set the context for all models and their data...🤭 If I'm being honest, I originally thought for useContext to work, the _provider component_ always had to be called `UserProvider` and we set the state for all models and their data in this one _provider component_. **THIS IS WHY IT'S IMPORTANT TO RESEARCH AND ASK QUESTIONS!** Keep in mind you can name this _provider component_ whatever you'd like. However, `UserProvider` makes sense because this component is technically providing data to other components who may need it. Naming it UserRocks would be a bit odd...

**R**emember **convention over configuration** is best practice. Since I have a User, Movie, Review, and Reply model, I want to separate my concerns and give each of them its very own _provider component_ where context will be set for that particular class and its instances: 

<center> <b> USER CONTEXT <b> </center>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0q0ko12zn3bl05k8ct8k.jpeg)

<center> <b> MOVIE CONTEXT <b> </center>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0d8snlv5b47011spuxcy.jpeg)

<center> <b> REVIEW CONTEXT <b> </center>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zu2zie1n6eemzxsqs4jk.jpeg)

<center> <b> REPLY CONTEXT <b> </center>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onim81a1uwmzdva8wf5w.jpeg)

Ahhh, suddenly my anxiety has calmed down. 💁🏽

**G**iving each model its own _provider component_ to set up context for their data allows for that separation of concern I mentioned earlier. This is where I can say 'Ok, I'm going to put all HTTP requests that relate to this particular model and its data and set state'. That way when the time comes I know exactly where to look, grab from, and update when working with a particular model and it's data in the backend from the frontend.


<center> <b> "VALUE" PROP <b> </center>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzx5fjx7cqecmdhhooch.jpeg)

**Notice** in the return of our _provider components_ we have what looks like a prop called value. Well, **that's because it is a prop and any child of a _provider component_ has access to that prop and its values!** Now what exactly are we setting the values to in this prop? Data that can be or needs to be shared with other components. Maybe something equivalent to an array of all movies that the Movie model holds in our backend or even an array of all the reviews that the Review model holds:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8h6s1onm8x6el7xdzjgz.jpeg)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tnphz4ex1gvunwozwce1.jpeg)

In the snaps above I'm using a _useEffect()_ to send a fetch to a registered route in the back end that will then be mapped to a controller action to render back JSON of all movies in the Movie model database. Within that fetch, I'm setting the movies into an empty array called 'movies' using state. Great, now I have the data I need for movies to render them to the front end. I might just need that array of movies for other purposes rather than just rendering the title, poster, year, and the cast of the movie. So I want to make context out of this array to possibly share this data with other child components that need it. More on that a bit later. I then pass that data under 'movies' as a prop under 'value=' in the case that I do need this data for child components. 

<center> <b> Provider Components have child components say whaaa????  <b> </center>

**W**ell, how do we make _provider components_ and their prop data available to other components within our app if technically it has no child components? Well, it doesn't have any children yet because we haven't given it any children. In our earlier example with _MoviePage_ and _ReviewCard_ I was able to share the data that the _MoviePage_ has and pass it onto _ReviewCard_ as a prop because _ReviewCard_ is its child! We imported _ReviewCard_ into the _MoviePage_ component and rendered whatever code is set up in _ReviewCard_ from the _MoviePage_ making ReviewC its child. However, without the data provided by the _MoviePage_ what originally was supposed to render visually to the user would not have been possible. 

**S**o if we want all components to have access to a provider component data we need to ensure that the provider components are wrapped around the top-level component of our application. To do so we need to import all provider components we'd like data from into our top-level component of the application and then proceed to wrap:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x5ch47jwr6j3usoifvxp.jpeg)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k3n2149mjkp33v75kjfz.jpeg)

**Voila!** There you have it, _useContext_ is set and ready to go! _No more prop drilling_. But how do we use _useContext_ throughout our child components? Let's say I have settings in my application where a user can update their username or user image:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i0nj7p6dfuatfkyx6mxg.jpeg)

Sure we can request the backend to update the user info through a fetch and change the user state, but what if we have a movie that has many reviews and these reviews render with an image and the username of the user who left the review?

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cez08zciho9am9twra8q.jpeg)

 We'd have to update the movie's state within that fetch request. This is where the realization of how great _useContext_ is. 

<center> <b> useContext IN ACTION <b> </center>

In my UserProvider component, I have fetches set up to update a user username and a user image:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s02ftjbskogrxywlx24s.jpeg)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8b2n2t52ruil55hdf98t.jpeg)

 I know because a movie has many reviews and these reviews are rendered with an image and the username of the user who left the review I will have to update my movies state. Let's say in theory I had set up the state of movies in the top-level component of my application. I might have to prop-drill the movie data down until I reached the child component I need to get to in order to update a state within this fetch. Because I set up context for my movie data I can easily import _useContext_ and _MovieContext_ into the child component of _MovieContext_, _User_Profile_. I also destructed my 'prop' _{ movies } equal to useContext( MovieContext )_. Remember, every provider component holds a _'value' prop_ :

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ldeul3s0g6i15yzjdm8l.jpeg)

I also imported _UserContext_ into my _User_Profile_ component _(a child of UserProvider)_ and destructed my props _updateUsername_ and _updateUserImage_ that hold a value of my fetch POST functions in _UserProvider_:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8x25ogybo9kkvfxuuzan.jpeg)

If you look back at my fetch POST functions set up in _UserProvider_ you can see it takes in a movies argument. You can see now because I imported _useContext_, _MovieContext_, and destructed my movies prop I'm able to pass in the movie data into my _updateUsernameSubmit_ and _updateUserImageSubmit_ functions for my form onSubmit events: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bm2jros5l5b780cvprbc.jpeg)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgapa244mffow2isz801.jpeg)

This will allow for an update on the state of movies so when a user updates their username or image not only will you seen an update on the users profile but also an update on a movies reviews. And guess what?! No **PROP DRILLING!**:

<center> <b> BEFORE UPDATE <b> </center>

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gs17t7gpkfa1yomebzt6.jpeg)

<center> <b> AFTER UPDATE <b> </center>

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6oqihkyt4sf9bqrd5hux.jpeg)


**RESOURCES**
1. [freeCodecamp](https://www.freecodecamp.org/news/context-api-in-react/#:~:text=It's%20important%20to%20note%20that,access%20to%20the%20shared%20data.)

2. [React](https://legacy.reactjs.org/docs/context.html)