{"id":4170,"date":"2022-02-15T15:19:37","date_gmt":"2022-02-15T23:19:37","guid":{"rendered":"https:\/\/coderpad.io\/?p=4170"},"modified":"2023-06-05T14:36:06","modified_gmt":"2023-06-05T21:36:06","slug":"rules-of-reacts-useeffect","status":"publish","type":"post","link":"https:\/\/coderpad.io\/blog\/development\/rules-of-reacts-useeffect\/","title":{"rendered":"Rules of React&#8217;s useEffect"},"content":{"rendered":"\n<p>React\u2019s <code>useEffect<\/code> is a powerful API with lots of capabilities, and therefore flexibility. Unfortunately, this flexibility often leads to abuse and misuse, which can greatly damage an app\u2019s stability.<\/p>\n\n\n\n<p>The good news is that if you follow a set of rules designated to protect you during coding, your application can be secure and performant.<\/p>\n\n\n\n<p>No, we\u2019re not talking about React\u2019s \u201c<a href=\"https:\/\/reactjs.org\/docs\/hooks-rules.html\" target=\"_blank\" rel=\"noopener\">Rules of Hooks<\/a>\u201d, which includes rules such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>No conditionally calling hooks<\/li>\n\n\n\n<li>Only calling hooks inside of hooks or component<\/li>\n\n\n\n<li>Always having items inside of the dependency array<\/li>\n<\/ul>\n\n\n\n<p>These rules are good, but can be detected automatically with linting rules. It&#8217;s good that they&#8217;re there (and maintained by Meta), but overall, we can pretend like everyone has them fixed because their IDE should throw a warning.<\/p>\n\n\n\n<p>Specifically, I want to talk about the rules that can only be caught during manual code review processes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Keep all side effects inside <code>useEffect<\/code><\/li>\n\n\n\n<li>Properly clean up side effects<\/li>\n\n\n\n<li>Don&#8217;t use <code>ref<\/code> in <code>useEffect<\/code><\/li>\n\n\n\n<li>Don&#8217;t use <code>[]<\/code> as a guarantee that something only happens once<\/li>\n<\/ul>\n\n\n\n<p>While these rules may seem obvious at first, we&#8217;ll be taking a deep dive into the &#8220;why&#8221; of each. As a result, you may learn something about how React works under the hood &#8211; even if you&#8217;re a React pro.<\/p>\n\n\n<aside class=\"\n    cta-banner\n     cta-banner--bg-blue      cta-banner--has-media \"\ndata-block-name=\"cta-banner\">\n    <div class=\"inner\">\n        <div class=\"content\">\n                            <h2 class=\"headline\">Learn how to run front-end developer interviews that don&#8217;t suck<\/h2>\n            \n                            <div class=\"cta-buttons\">\n                                    <a href=\"https:\/\/coderpad.io\/blog\/interviewing\/5-tips-for-interviewing-frontend\/\" class=\"button  js-cta--read-our-guide\" data-ga-category=\"CTA\" data-ga-label=\"Learn how to run front-end developer interviews that don&#039;t suck|Read our guide\">Read our guide<\/a>\n                                <\/div>\n                    <\/div>\n                    <div class=\"media\">\n                <img loading=\"lazy\" decoding=\"async\" width=\"432\" height=\"342\" src=\"https:\/\/coderpad.io\/wp-content\/uploads\/2022\/08\/Illustration-of-man-with-beard-popping-out-of-computer-chat.png\" class=\"attachment-large size-large\" alt=\"\" srcset=\"https:\/\/coderpad.io\/wp-content\/uploads\/2022\/08\/Illustration-of-man-with-beard-popping-out-of-computer-chat.png 432w, https:\/\/coderpad.io\/wp-content\/uploads\/2022\/08\/Illustration-of-man-with-beard-popping-out-of-computer-chat-300x238.png 300w\" sizes=\"auto, (max-width: 432px) 100vw, 432px\" \/>\n            <\/div>\n            <\/div>\n<\/aside>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"keep-all-side-effects-inside-useeffect\">Keep all side effects inside <code>useEffect<\/code><\/h2>\n\n\n\n<p>For anyone familiar with React\u2019s docs, you\u2019ll know that this rule has been repeated over and over again. But why? Why is this a rule?<\/p>\n\n\n\n<p>After all, what would prevent you from storing logic inside of a <code>useMemo<\/code> and simply having an empty dependency array to prevent it from running more than once?<\/p>\n\n\n\n<p>Let\u2019s try that out by running a network request inside of a <code>useMemo<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;activity, setActivity] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> effectFn = React.useMemo(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0\u00a0\u00a0 <span class=\"hljs-comment\">\/\/ Make a network request here<\/span>\n\u00a0\u00a0\u00a0 fetch(<span class=\"hljs-string\">\"https:\/\/www.boredapi.com\/api\/activity\"<\/span>)\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> res.json())\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> setActivity(res.activity));\n\u00a0 }, &#91;])\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{activity}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div\n\tclass=\"sandbox-embed responsive-embed \"\n\tstyle=\"padding-top: 125%\"\ndata-block-name=\"coderpad-sandbox-embed\">\n\t<iframe src=\"https:\/\/embed.coderpad.io\/sandbox?question_id=231338&#038;use_question_button\" width=\"640\" height=\"800\" loading=\"lazy\" aria-label=\"Try out the CoderPad sandbox\"><\/iframe>\n<\/div>\n\n\n\n<p>Huh. It works first try without any immediately noticeable downsides. This works because <code>fetch<\/code> is asynchronous, meaning that it doesn\u2019t block the <a href=\"https:\/\/www.youtube.com\/watch?v=8aGhZQkoFbQ&amp;vl=en\" target=\"_blank\" rel=\"noopener\">event loop<\/a>. Instead, let\u2019s change that code to be a synchronous <code>XHR<\/code> request and see if that works too.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getActivity<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\u00a0 <span class=\"hljs-keyword\">var<\/span> request = <span class=\"hljs-keyword\">new<\/span> XMLHttpRequest();\n\u00a0 request.open(<span class=\"hljs-string\">'GET'<\/span>, <span class=\"hljs-string\">'https:\/\/www.boredapi.com\/api\/activity'<\/span>, <span class=\"hljs-literal\">false<\/span>);\u00a0 <span class=\"hljs-comment\">\/\/ `false` makes the request synchronous<\/span>\n\u00a0 request.send(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-built_in\">JSON<\/span>.parse(request.responseText);\n}\n\n<span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;data, setData] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> effectFn = React.useMemo(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0\u00a0\u00a0 setData(getActivity().activity);\n\u00a0 }, &#91;]);\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Hello, world! {data}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div\n\tclass=\"sandbox-embed responsive-embed \"\n\tstyle=\"padding-top: 125%\"\ndata-block-name=\"coderpad-sandbox-embed\">\n\t<iframe src=\"https:\/\/embed.coderpad.io\/sandbox?question_id=231342&#038;use_question_button\" width=\"640\" height=\"800\" loading=\"lazy\" aria-label=\"Try out the CoderPad sandbox\"><\/iframe>\n<\/div>\n\n\n\n<p>Here, we can see behavior that we might not expect to see. When using useMemo alongside a blocking method, the entire screen will halt before drawing anything. The initial paint is then made after the fetch is finally finished.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/useMemoRendering.mp4\"><\/video><\/figure>\n\n\n\n<p>However, if we use useEffect instead, this does not occur.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/useEffectRendering.mp4\"><\/video><\/figure>\n\n\n\n<p>Here, we can see the initial paint occur, drawing the \u201cHello\u201d message before the blocking network call is made.<\/p>\n\n\n\n<p>Why does this happen?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"understanding-hook-lifecycles\">Understanding hook lifecycles<\/h3>\n\n\n\n<p>The reason <code>useEffect<\/code> is still able to paint but useMemo cannot is because of the timings of each of these hooks. You can think of <code>useMemo<\/code> as occurring right in line with the rest of your render code.<\/p>\n\n\n\n<p>In terms of timings, the two pieces of code are very similar:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;data, setData] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> effectFn = React.useMemo(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0\u00a0\u00a0 setData(getActivity().activity);\n\u00a0 }, &#91;]);\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Hello, world! {data}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;data, setData] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 setData(getActivity().activity);\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Hello, world! {data}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This inlining behavior occurs because <code>useMemo<\/code> runs during the \u201crender\u201d phase of a component. <code>useEffect<\/code>, on the other hand, runs <strong>after<\/strong> a component renders out, which allows an initial render before the blocking behavior halts things for us.<\/p>\n\n\n\n<p>Those among you that know of \u201cuseLayoutEffect\u201d may think you have found a gotcha in what I just said.<\/p>\n\n\n\n<p>\u201cAhh, but wouldn\u2019t useLayoutEffect also prevent the browser from drawing until the network call is completed?\u201d<\/p>\n\n\n\n<p>Not quite! You see, while useMemo runs during the render phase, useLayoutEffect runs during the \u201c<em>commit\u201d<\/em> phase and therefore renders the initial contents to screen first.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p><a href=\"https:\/\/reactjs.org\/docs\/hooks-reference.html#uselayouteffect\" target=\"_blank\" rel=\"noopener\">useLayoutEffect\u2019s signature is identical to useEffect, but it fires synchronously after all DOM mutations.<\/a><\/p>\n<\/blockquote>\n\n\n\n<p>See, the commit phase is the part of a component\u2019s lifecycle <em>after<\/em> React is done asking all the components what they want the UI to look like, has done all the diffing, and is ready to update the DOM.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/coderpad.io\/wp-content\/uploads\/2022\/02\/img_620c350969cbd.png\" alt=\"\" width=\"386\" height=\"548\"\/><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>If you\u2019d like to learn more about how React does its UI diffing and what this process all looks like under the hood, take a look at <a href=\"https:\/\/overreacted.io\/react-as-a-ui-runtime\/\" target=\"_blank\" rel=\"noopener\">Dan Abramov\u2019s wonderful \u201cReact as a UI Runtime\u201d post<\/a>.<\/p>\n\n\n\n<p>There\u2019s also <a href=\"https:\/\/github.com\/Wavez\/react-hooks-lifecycle\" target=\"_blank\" rel=\"noopener\">this awesome chart demonstrating how all of the hooks tie in together<\/a> that our chart is a simplified version of.<\/p>\n<\/blockquote>\n\n\n\n<p>Now, this isn\u2019t to say that you should optimize your code to work effectively with blocking network calls. After all, while <code>useEffect<\/code> allows you to render your code, a blocking network request still puts you in the uncomfortable position of your user being unable to interact with your page.<br><br>Because JavaScript is single-threaded, a blocking function will prevent user interaction from being processed in the event loop.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>If you read the last sentence and are scratching your head, you\u2019re not alone. The idea of JavaScript being single-threaded, what an \u201cevent loop\u201d is, and what \u201cblocking\u201d means are all quite confusing at first.<\/p>\n\n\n\n<p>We suggest taking a look at <a href=\"https:\/\/www.youtube.com\/watch?v=8aGhZQkoFbQ\" target=\"_blank\" rel=\"noopener\">this great explainer talk from Philip Robers<\/a> to understand more.<\/p>\n<\/blockquote>\n\n\n\n<p>That said, this isn\u2019t the only scenario where the differences between <code>useMemo<\/code> and <code>useEffect<\/code> cause misbehavior with side effects. Effectively, they\u2019re two different tools with different usages and attempting to merge them often breaks things.<\/p>\n\n\n\n<p>Attempting to use <code>useMemo<\/code> in place of <code>useEffect<\/code> leads to scenarios that can introduce bugs, and it may not be obvious what\u2019s going wrong at first. After long enough, with enough of these floating about in your application, it\u2019s sort of \u201cdeath by a thousand paper-cuts\u201d.<\/p>\n\n\n\n<p>These papercuts aren&#8217;t the only problem, however. After all, the APIs for useEffect and useMemo are not the same. This incongruity between APIs is especially pronounced for network requests because a key feature is missing from the <code>useMemo<\/code> API: effect cleanup.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"always-clean-up-your-side-effects\">Always clean up your side effects<\/h2>\n\n\n\n<p>Occasionally, when using <code>useEffect<\/code>, you may be left with something that requires cleanup. A classic example of this might be a network call.<br><br>Say you have an application to give bored users an activity to do at home. Let\u2019s use a network request that retrieves an activity from an API:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;activity, setActivity] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0 React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0\u00a0\u00a0 fetch(<span class=\"hljs-string\">\"https:\/\/www.boredapi.com\/api\/activity\"<\/span>)\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> res.json())\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> setActivity(res.activity));\n\u00a0 }, &#91;])\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{activity}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>While this works for a single activity, what happens when the user completes the activity?&nbsp;<\/p>\n\n\n\n<p>Let\u2019s give them a button to rotate between new activities and include a count of how many times the user has requested an activity.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;activity, setActivity] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;num, setNum] = React.useState(<span class=\"hljs-number\">1<\/span>);\n\n\u00a0 React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\u00a0\u00a0\u00a0 <span class=\"hljs-comment\">\/\/ Make a network request here<\/span>\n\u00a0\u00a0\u00a0 fetch(<span class=\"hljs-string\">\"https:\/\/www.boredapi.com\/api\/activity\"<\/span>)\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> res.json())\n\u00a0 \u00a0\u00a0\u00a0 .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> setActivity(res.activity));\n\u00a0\u00a0\u00a0 <span class=\"hljs-comment\">\/\/ Re-run this effect when `num` is updated during render<\/span>\n\u00a0 }, &#91;num])\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> (\n\u00a0 <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\u00a0\u00a0\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>You should: {activity}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\u00a0\u00a0\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>You have done {num} activities<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\u00a0\u00a0\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setNum(num + 1)}&gt;Request new activity<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\u00a0\n\u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\u00a0 )\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Just as we intended, we get a new network activity if we press the button. We can even press the button multiple times to get a new activity per press.<br><br>But wait, what happens if we slow down our network speed and press the \u201crequest\u201d button rapidly?<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/before_signal.mp4\"><\/video><\/figure>\n\n\n\n<p>Oh no! Even tho we\u2019ve stopped clicking the button, our network requests are still coming in. This gives us a sluggish feeling experience, especially when latency times between network calls are high.<\/p>\n\n\n\n<p>Well, this is where our cleanup would come into effect. Let\u2019s add an <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/AbortSignal\" target=\"_blank\" rel=\"noopener\">AbortSignal<\/a> to cancel a request when we request a new one.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> EffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> &#91;activity, setActivity] = React.useState(<span class=\"hljs-literal\">null<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;num, setNum] = React.useState(<span class=\"hljs-number\">1<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> controller = <span class=\"hljs-keyword\">new<\/span> AbortController();\n    <span class=\"hljs-keyword\">const<\/span> signal = controller.signal;\n\n    <span class=\"hljs-comment\">\/\/ Make a network request here<\/span>\n    fetch(<span class=\"hljs-string\">\"https:\/\/www.boredapi.com\/api\/activity\"<\/span>, {signal})\n      .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> res.json())\n      .then(<span class=\"hljs-function\"><span class=\"hljs-params\">res<\/span> =&gt;<\/span> setActivity(res.activity));\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      controller.abort();\n    }\n    <span class=\"hljs-comment\">\/\/ Re-run this effect when `num` is updated during render<\/span>\n  }, &#91;num])\n\n  <span class=\"hljs-keyword\">return<\/span> (\n  <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>You should: {activity}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>You have done {num} activities<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setNum(num + 1)}&gt;Request new activity<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span> \n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If we open our network request tab, you\u2019ll notice how our network calls are now being canceled when we initialize a new one.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/coderpad.io\/wp-content\/uploads\/2022\/02\/img_620c350c0cd32.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>This is a good thing! It means that instead of a jarring experience of jumpiness, you\u2019ll now only see a single activity after the end of a chain of clicking.<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/after_signal.mp4\"><\/video><\/figure>\n\n\n\n<p>While this may seem like a one-off that we created ourselves using artificial network slowdowns, this is the real-world experience users on slow networks may experience!<\/p>\n\n\n\n<p>What\u2019s more, when you consider API timing differences, this problem may be even more widespread.<\/p>\n\n\n\n<p>Let\u2019s say that you\u2019re using a <a href=\"https:\/\/coderpad.io\/blog\/development\/why-react-18-broke-your-app\/\">new React concurrent feature<\/a>, which may cause an interrupted render, forcing a new network call before the other has finished.<\/p>\n\n\n\n<p>The first call hangs on the server for slightly longer for whatever reason and takes 500ms, but the second call goes through immediately in 20ms. But oh no, during that 480ms there was a change in the data!<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/coderpad.io\/wp-content\/uploads\/2022\/02\/img_620c350ca9930.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>This means that our <code>.then<\/code> which runs <code>setActivity<\/code> will execute on the first network call \u2013 complete with stale data (showing \u201c10,000\u201d) \u2013<strong>after<\/strong> the second network call.<\/p>\n\n\n\n<p>This is important to catch early, because these shifts in behavior can be immediately noticeable to a user when it happens. These issues are also often particularly difficult to find and work through after the fact.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"don-t-use-refs-in-useeffect\">Don\u2019t use refs in useEffect<\/h2>\n\n\n\n<p>If you\u2019ve ever used a useEffect to apply an <code>addEventListener<\/code>, you may have written something like the following:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> RefEffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> buttonRef = React.useRef();\n\n  <span class=\"hljs-keyword\">const<\/span> &#91;count, setCount] = React.useState(<span class=\"hljs-number\">0<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buttonAdder<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n        setCount(<span class=\"hljs-function\"><span class=\"hljs-params\">v<\/span> =&gt;<\/span> v + <span class=\"hljs-number\">1<\/span>);\n    }\n   \n    buttonRef.current.addEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n        buttonRef.current.removeEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);    \n    }\n  }, &#91;buttonRef.current])\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{buttonRef}<\/span>&gt;<\/span>Click me<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div\n\tclass=\"sandbox-embed responsive-embed \"\n\tstyle=\"padding-top: 125%\"\ndata-block-name=\"coderpad-sandbox-embed\">\n\t<iframe src=\"https:\/\/embed.coderpad.io\/sandbox?question_id=231346&#038;use_question_button\" width=\"640\" height=\"800\" loading=\"lazy\" aria-label=\"Try out the CoderPad sandbox\"><\/iframe>\n<\/div>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/button_incrementing.mp4\"><\/video><\/figure>\n\n\n\n<p>While this might make intuitive sense due to utilizing <code>useEffect<\/code>\u2019s cleanup, this code is actually not correct. You should not utilize a <code>ref<\/code> or <code>ref.current<\/code> inside of a dependency array for a hook.<\/p>\n\n\n\n<p>This is because <strong>changing refs does not force a re-render and therefore useEffect never runs when the value changes.<\/strong><\/p>\n\n\n\n<p>While most assume that <code>useEffect<\/code> \u201clistens\u201d for changes in this array and runs the effect when it changes, this is an inaccurate mental model.<\/p>\n\n\n\n<p>A more apt mental model might be: \u201cuseEffect only runs at most once per render. However, as an optimization, I can pass an array to prevent the side effect from running if the variable references inside of the array have not changed.\u201d<\/p>\n\n\n\n<p>This shift in understanding is important because the first version can easily lead to bugs in your app. For example, instead of rendering out the button immediately, let\u2019s say that we need to defer the rendering for some reason.<\/p>\n\n\n\n<p>Simple enough, we\u2019ll add a <code>setTimeout<\/code> and a boolean to render the button.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> RefEffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span>=&gt;<\/span>{\n  <span class=\"hljs-keyword\">const<\/span> buttonRef = React.useRef();\n\n  <span class=\"hljs-keyword\">const<\/span> &#91;count, setCount] = React.useState(<span class=\"hljs-number\">0<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buttonAdder<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      setCount(<span class=\"hljs-function\"><span class=\"hljs-params\">v<\/span> =&gt;<\/span> v + <span class=\"hljs-number\">1<\/span>);\n    }\n          <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'UseEffect has run'<\/span>);\n          <span class=\"hljs-comment\">\/\/ This will throw an error during the first render otherwise<\/span>\n    <span class=\"hljs-keyword\">if<\/span> (!buttonRef.current) <span class=\"hljs-keyword\">return<\/span>;\n   \n    buttonRef.current.addEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      buttonRef.current.removeEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);    \n    }\n  }, &#91;buttonRef.current])\n\n   \n  <span class=\"hljs-keyword\">const<\/span> &#91;shouldRender, setShouldRender] = React.useState(<span class=\"hljs-literal\">false<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> timer = setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      setShouldRender(<span class=\"hljs-literal\">true<\/span>);\n    }, <span class=\"hljs-number\">1000<\/span>);\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      clearTimeout(timer);\n      setShouldRender(<span class=\"hljs-literal\">false<\/span>);\n    }\n  }, &#91;]);\n\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    {shouldRender &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{buttonRef}<\/span>&gt;<\/span>Click me<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>}\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div\n\tclass=\"sandbox-embed responsive-embed  sandbox-embed--full-width\"\n\tstyle=\"padding-top: 125%\"\ndata-block-name=\"coderpad-sandbox-embed\">\n\t<iframe src=\"https:\/\/embed.coderpad.io\/sandbox?question_id=231348&#038;use_question_button\" width=\"640\" height=\"800\" loading=\"lazy\" aria-label=\"Try out the CoderPad sandbox\"><\/iframe>\n<\/div>\n\n\n\n<p>Now, if we wait a second for the button to render and click it, our counter doesn\u2019t go up!<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/02\/button_not_incrementing.mp4\"><\/video><\/figure>\n\n\n\n<p>This is because once our <code>ref<\/code> is set after the initial render, it doesn\u2019t trigger a re-render and our <code>useEffect<\/code> never runs.<\/p>\n\n\n\n<p>A better way to write this would be to utilize a <a href=\"https:\/\/unicorn-utterances.com\/posts\/react-refs-complete-story#callback-refs\" target=\"_blank\" rel=\"noopener\">\u201ccallback ref\u201d<\/a>, and then use a <code>useState<\/code> to force a re-render when it\u2019s set.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> RefEffectComp = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span>=&gt;<\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#91;buttonEl, setButtonEl] = React.useState();\n\n  <span class=\"hljs-keyword\">const<\/span> &#91;count, setCount] = React.useState(<span class=\"hljs-number\">0<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">buttonAdder<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      setCount(<span class=\"hljs-function\"><span class=\"hljs-params\">v<\/span> =&gt;<\/span> v + <span class=\"hljs-number\">1<\/span>);\n    }\n   \n    <span class=\"hljs-keyword\">if<\/span> (!buttonEl) <span class=\"hljs-keyword\">return<\/span>;\n   \n    buttonEl.addEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      buttonEl.removeEventListener(<span class=\"hljs-string\">'click'<\/span>, buttonAdder);    \n    }\n  }, &#91;buttonEl])\n\n   \n  <span class=\"hljs-keyword\">const<\/span> &#91;shouldRender, setShouldRender] = React.useState(<span class=\"hljs-literal\">false<\/span>);\n\n  React.useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> timer = setTimeout(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      setShouldRender(<span class=\"hljs-literal\">true<\/span>);\n    }, <span class=\"hljs-number\">1000<\/span>);\n   \n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      clearTimeout(timer);\n      setShouldRender(<span class=\"hljs-literal\">false<\/span>);\n    }\n  }, &#91;]);\n\n\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{count}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n    {shouldRender &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{buttonElRef<\/span> =&gt;<\/span> setButtonEl(buttonElRef)}&gt;Click me<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>}\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will force the re-render when <code>ref<\/code> is set after the initial render and, in turn, cause the <code>useEffect<\/code> to trigger as expected.<\/p>\n\n\n\n<p>To be fair, this \u201crule\u201d is more of a soft rule than anything. There are absolutely instances &#8211; such as setTimeout timers &#8211; where utilizing a ref inside of a useEffect make sense. Just make sure you have a proper mental model about refs and useEffect and you\u2019ll be fine.&nbsp;<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>Want to refine your understanding of refs even further? <a href=\"https:\/\/unicorn-utterances.com\/posts\/react-refs-complete-story\" target=\"_blank\" rel=\"noopener\">See my article outlining the important details of refs for more.<\/a><\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"don-t-expect-an-empty-dependency-array-to-only-run-once\">Don\u2019t expect an empty dependency array to only run once<\/h2>\n\n\n\n<p>While previous versions of React allowed you to utilize an empty array to guarantee that a <code>useEffect<\/code> would only run once,<a href=\"https:\/\/coderpad.io\/blog\/development\/why-react-18-broke-your-app\/\">React 18 changed this behavior<\/a>. As a result, now <code>useEffect<\/code> may run any number of times when an empty dependency array passes, in particular when a<a href=\"https:\/\/github.com\/reactwg\/react-18\/discussions\/46#discussioncomment-846786\" target=\"_blank\" rel=\"noopener\">concurrent feature is utilized<\/a>.<\/p>\n\n\n\n<p>Concurrent features are new to React 18 and allow React to pause, halt, and remount a component whenever React sees it appropriate.<\/p>\n\n\n\n<p>As a result, this may break various aspects of your code.<\/p>\n\n\n\n<p>You can <a href=\"https:\/\/coderpad.io\/blog\/development\/why-react-18-broke-your-app\/\">read more about how an empty dependency array can break in your app from our article about React 18\u2019s changes to mounting.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>React\u2019s useEffect is an instrumental part of modern React applications. Now that you know more about its internals and the rules around it, you can build stronger and more dynamic programs!<\/p>\n\n\n\n<p>If you want to continue learning skills that will help make your React apps better, I suggest taking a look at <a href=\"https:\/\/coderpad.io\/blog\/development\/master-react-unidirectional-data-flow\/\">our guide to React Unidirectionality<\/a>, which outlines a good way to keep your application flow more organized.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>useEffect is prolific in React apps. Here are four rules associated with the hook and in-depth explanations of why they&#8217;re important.<\/p>\n","protected":false},"author":1,"featured_media":4197,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[],"persona":[29],"blog-programming-language":[61],"keyword-cluster":[],"class_list":["post-4170","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"_links":{"self":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/4170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/comments?post=4170"}],"version-history":[{"count":40,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/4170\/revisions"}],"predecessor-version":[{"id":32700,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/4170\/revisions\/32700"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media\/4197"}],"wp:attachment":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media?parent=4170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/categories?post=4170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/tags?post=4170"},{"taxonomy":"persona","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/persona?post=4170"},{"taxonomy":"blog-programming-language","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/blog-programming-language?post=4170"},{"taxonomy":"keyword-cluster","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/keyword-cluster?post=4170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}