Introduction
While working on my most recent project I ran into an issue that stumped me. It had to do with these snippets of code.
Part I - Understanding the Error and Getting More Familiar with Debugging tools
This function and this ternary expression were giving me a real headache. When the component loaded and these 2 snippets of code ran, they would both throw the same error at me. The error essentially told me that ‘recipe.user.id’ and ‘recipe.steps’ were null. The first thing I did was ‘console.log(recipe.steps)’ in order to see if it was really null. The console log spit out a valid Json object with the nested steps data I was trying to access. This honestly only added to my confusion. I was sitting there with my 2 project partners, racking my brain about what could be wrong.
I decided to console log my ‘recipe.user.id’ as well, and the same thing happened; I got valid Json data back. So why then was this code breaking, why was it saying everything was null if my console logs were showing something different?
Eventually, after a recommendation, I decided to use the tool, ‘debugger.’ Debugger freezes the code in place and lets you check out specific variables in the console.
After adding the debugger and freezing my code in place, I decided to check ‘recipe.steps', and who would have guessed it (I’m sure plenty of people, but humor me), ‘recipe.steps’ was returning null. Not only that, even just ‘recipe’ was returning null. Now I was confused, why was ‘recipe’ null in the debugger but not in my console log?
The reason is because ‘console.logs’ behavior is inherently different from something like a ‘.map’ or a ternary expression. Rather than being able to log null like a ‘console.log’ can, ‘.map’ and ternary expressions can’t just work off of null; if something is null, they break and throw errors. The console log was running every time the state changed, so once the recipe really did show up, the component would run again, and my console log would show me what I wanted. My issue was that these functions and expressions were running before my recipe data fully showed up and would break rather than just running until it worked.
Part II - Finding a Fix and Diving into Promises and Async/Await
So, now I knew what my issue was, but I wasn’t totally sure how to resolve it. Do I just use a sort of time out, do I need to render null on the page until ‘recipe’ is loaded? As a newer developer, I was having a hard time thinking of a way to navigate this issue, and that's when I remembered promises and asynchronous code.
I didn’t exactly know how, but I thought that this avenue may be able to resolve my issue, so I decided to dive in. I read through a lot of documentation and watched a lot of youtube videos to get more familiar with ‘Promises.’ I learned that a ‘Promise’ is an object that represents what you want, it is a placeholder for a value that you may not have yet. In this case, this promise was a placeholder for the ‘recipe’ that was taking a little bit of time to get there. It could essentially tell my code, “hey I know that ‘recipe’ isn’t here yet, but I promise it will be, just take my word for it.” It felt like I was moving in the right direction, I just needed to implement it.
Part III - Implementation to Code
While researching ‘Promises’ I also came across the keywords ‘async’ and ‘await.’ The documentation and videos on these keywords showed me that they were exactly what I needed in order to get this ‘Promise’ working. ‘Async’ and ‘await’ allow us to write code that looks synchronous, while actually being asynchronous. To use async/await, you first need to define a function as async. This tells JavaScript that the function contains async code, and that it will return a Promise. Then, you can use the await keyword inside the function to wait for a Promise to resolve before moving on to the next line of code. Here is how I applied it to my code:
While the data is being fetched, the component will render a "Loading..." message by checking if ‘recipe’ has arrived. Once the data has been fetched and stored in the component's state, the promise will be fulfilled, ‘recipe’ will no longer be null, and the component will render the data instead of a loading div.
Part IV - Conclusion
In the end, even though bugs can make you want to pull your hair, this debugging led me on an awesome journey that has made me a better developer. Through trial and error, we can better ourselves and learn something new. So next time you get a bug, don’t pull your hair out, think of it as a learning opportunity, and once all else fails, then you can start pulling.
Top comments (0)