<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>This Week In React - Articles</title>
        <link>https://thisweekinreact.com/articles</link>
        <description>Articles published on the This Week In React blog</description>
        <lastBuildDate>Tue, 06 Sep 2022 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[useSyncExternalStore - The underrated React API]]></title>
            <link>https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api</link>
            <guid>https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api</guid>
            <pubDate>Tue, 06 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[You might have heard of useSyncExternalStore(), a new React 18 hook to subscribe to external data sources. It is often used internally by state management libraries - like Redux - to implement a selector system.]]></description>
            <content:encoded><![CDATA[<p>You might have heard of <a href="https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore" target="_blank" rel="noopener noreferrer"><code>useSyncExternalStore()</code></a>, a new React 18 hook to <strong>subscribe to external data sources</strong>. It is often used internally by state management libraries - like <a href="https://github.com/reduxjs/react-redux/pull/1808" target="_blank" rel="noopener noreferrer">Redux</a> - to implement a <strong>selector system</strong>.</p>
<p>But what about using <code>useSyncExternalStore()</code> in your own application code?</p>
<p>In this interactive article, I want to present you a problem: <strong>over-returning React hooks triggering useless re-renders</strong>. We will see how <code>useSyncExternalStore()</code> can be a good fix.</p>
<p><img decoding="async" loading="lazy" alt="social card" src="https://thisweekinreact.com/assets/images/social-card-8c3d2564cca50e6a46ba0d78375e6d0e.png" width="2400" height="1350" class="img_SS3x"></p>
<div class="card subscribeFormEmbed_aAcT"><p><strong>Don't miss the next email!</strong></p><div>
<script src="https://f.convertkit.com/ckjs/ck.5.js"></script>
      <form action="https://app.convertkit.com/forms/3472133/subscriptions" class="seva-form formkit-form" method="post" data-sv-form="3472133" data-uid="8d653b97b6" data-format="inline" data-version="5" data-options="{&quot;settings&quot;:{&quot;after_subscribe&quot;:{&quot;action&quot;:&quot;redirect&quot;,&quot;success_message&quot;:&quot;Success! Now check your email to confirm your subscription.&quot;,&quot;redirect_url&quot;:&quot;https://thisweekinreact.com/workflow/confirm-your-email&quot;},&quot;analytics&quot;:{&quot;google&quot;:null,&quot;fathom&quot;:null,&quot;facebook&quot;:null,&quot;segment&quot;:null,&quot;pinterest&quot;:null,&quot;sparkloop&quot;:null,&quot;googletagmanager&quot;:null},&quot;modal&quot;:{&quot;trigger&quot;:&quot;timer&quot;,&quot;scroll_percentage&quot;:null,&quot;timer&quot;:5,&quot;devices&quot;:&quot;all&quot;,&quot;show_once_every&quot;:15},&quot;powered_by&quot;:{&quot;show&quot;:false,&quot;url&quot;:&quot;https://convertkit.com/features/forms?lmref=d0748g&amp;utm_campaign=poweredby&amp;utm_content=form&amp;utm_medium=referral&amp;utm_source=dynamic&quot;},&quot;recaptcha&quot;:{&quot;enabled&quot;:false},&quot;return_visitor&quot;:{&quot;action&quot;:&quot;show&quot;,&quot;custom_content&quot;:&quot;&quot;},&quot;slide_in&quot;:{&quot;display_in&quot;:&quot;bottom_right&quot;,&quot;trigger&quot;:&quot;timer&quot;,&quot;scroll_percentage&quot;:null,&quot;timer&quot;:5,&quot;devices&quot;:&quot;all&quot;,&quot;show_once_every&quot;:15},&quot;sticky_bar&quot;:{&quot;display_in&quot;:&quot;top&quot;,&quot;trigger&quot;:&quot;timer&quot;,&quot;scroll_percentage&quot;:null,&quot;timer&quot;:5,&quot;devices&quot;:&quot;all&quot;,&quot;show_once_every&quot;:15}},&quot;version&quot;:&quot;5&quot;}" min-width="400 500 600 700 800"><div data-style="clean"><ul class="formkit-alert formkit-alert-error" data-element="errors" data-group="alert"></ul><div data-element="fields" data-stacked="false" class="seva-fields formkit-fields"><div class="formkit-field"><input class="formkit-input" name="email_address" aria-label="Email Address" placeholder="Email Address" required="" type="email" style="color: rgb(0, 0, 0); border-color: rgb(227, 227, 227); border-radius: 4px; font-weight: 700;"></div><button data-element="submit" class="formkit-submit formkit-submit" style="color: rgb(255, 255, 255); background-color: rgb(0, 54, 92); border-radius: 4px; font-weight: 700;"><div class="formkit-spinner"><div></div><div></div><div></div></div><span>Subscribe now!</span></button></div></div><style>.formkit-form[data-uid="8d653b97b6"] *{box-sizing:border-box}.formkit-form[data-uid="8d653b97b6"]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.formkit-form[data-uid="8d653b97b6"] legend{font-size:inherit;border:none;margin-bottom:10px;padding:0;display:table;position:relative}.formkit-form[data-uid="8d653b97b6"] fieldset{border:0;min-width:0;margin:0;padding:.01em 0 0}.formkit-form[data-uid="8d653b97b6"] body:not(:-moz-handler-blocked) fieldset{display:table-cell}.formkit-form[data-uid="8d653b97b6"] h1,.formkit-form[data-uid="8d653b97b6"] h2,.formkit-form[data-uid="8d653b97b6"] h3,.formkit-form[data-uid="8d653b97b6"] h4,.formkit-form[data-uid="8d653b97b6"] h5,.formkit-form[data-uid="8d653b97b6"] h6{color:inherit;font-size:inherit;font-weight:inherit}.formkit-form[data-uid="8d653b97b6"] h2{margin:1em 0;font-size:1.5em}.formkit-form[data-uid="8d653b97b6"] h3{margin:1em 0;font-size:1.17em}.formkit-form[data-uid="8d653b97b6"] p{color:inherit;font-size:inherit;font-weight:inherit}.formkit-form[data-uid="8d653b97b6"] ol:not([template-default]),.formkit-form[data-uid="8d653b97b6"] ul:not([template-default]),.formkit-form[data-uid="8d653b97b6"] blockquote:not([template-default]){text-align:left}.formkit-form[data-uid="8d653b97b6"] p:not([template-default]),.formkit-form[data-uid="8d653b97b6"] hr:not([template-default]),.formkit-form[data-uid="8d653b97b6"] blockquote:not([template-default]),.formkit-form[data-uid="8d653b97b6"] ol:not([template-default]),.formkit-form[data-uid="8d653b97b6"] ul:not([template-default]){color:inherit;font-style:initial}.formkit-form[data-uid="8d653b97b6"] .ordered-list,.formkit-form[data-uid="8d653b97b6"] .unordered-list{padding-left:1em;list-style-position:outside!important}.formkit-form[data-uid="8d653b97b6"] .list-item{padding-left:0}.formkit-form[data-uid="8d653b97b6"][data-format=modal],.formkit-form[data-uid="8d653b97b6"][data-format=slide\ in],.formkit-form[data-uid="8d653b97b6"][data-format=sticky\ bar]{display:none}.formkit-sticky-bar .formkit-form[data-uid="8d653b97b6"][data-format=sticky\ bar]{display:block}.formkit-form[data-uid="8d653b97b6"] .formkit-input,.formkit-form[data-uid="8d653b97b6"] .formkit-select,.formkit-form[data-uid="8d653b97b6"] .formkit-checkboxes{width:100%}.formkit-form[data-uid="8d653b97b6"] .formkit-button,.formkit-form[data-uid="8d653b97b6"] .formkit-submit{color:#fff;cursor:pointer;text-align:center;cursor:pointer;vertical-align:middle;border:0;border-radius:5px;margin-bottom:15px;padding:0;font-size:15px;font-weight:500;display:inline-block;position:relative;overflow:hidden}.formkit-form[data-uid="8d653b97b6"] .formkit-button:hover,.formkit-form[data-uid="8d653b97b6"] .formkit-submit:hover,.formkit-form[data-uid="8d653b97b6"] .formkit-button:focus,.formkit-form[data-uid="8d653b97b6"] .formkit-submit:focus{outline:none}.formkit-form[data-uid="8d653b97b6"] .formkit-button:hover>span,.formkit-form[data-uid="8d653b97b6"] .formkit-submit:hover>span,.formkit-form[data-uid="8d653b97b6"] .formkit-button:focus>span,.formkit-form[data-uid="8d653b97b6"] .formkit-submit:focus>span{background-color:#0000001a}.formkit-form[data-uid="8d653b97b6"] .formkit-button>span,.formkit-form[data-uid="8d653b97b6"] .formkit-submit>span{padding:12px 24px;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out;display:block}.formkit-form[data-uid="8d653b97b6"] .formkit-input{background:#fff;border:1px solid #e3e3e3;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;margin:0;padding:12px;font-size:15px;line-height:1.4;-webkit-transition:border-color .3s ease-out;transition:border-color .3s ease-out}.formkit-form[data-uid="8d653b97b6"] .formkit-input:focus{border-color:#1677be;outline:none;-webkit-transition:border-color .3s;transition:border-color .3s}.formkit-form[data-uid="8d653b97b6"] .formkit-input::-webkit-input-placeholder{color:inherit;opacity:.8}.formkit-form[data-uid="8d653b97b6"] .formkit-input::placeholder{color:inherit;opacity:.8}.formkit-form[data-uid="8d653b97b6"] .formkit-input:-ms-input-placeholder{color:inherit;opacity:.8}.formkit-form[data-uid="8d653b97b6"] .formkit-input::placeholder{color:inherit;opacity:.8}.formkit-form[data-uid="8d653b97b6"] [data-group=dropdown]{width:100%;display:inline-block;position:relative}.formkit-form[data-uid="8d653b97b6"] [data-group=dropdown]:before{content:"";pointer-events:none;z-index:999;border:6px solid #0000;border-top-color:#4f4f4f;border-bottom-width:0;width:0;height:0;position:absolute;top:calc(50% - 2.5px);right:10px}.formkit-form[data-uid="8d653b97b6"] [data-group=dropdown] select{cursor:pointer;color:#333;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#fff;border:1px solid #e3e3e3;width:100%;height:auto;margin-bottom:0;padding:12px 25px 12px 12px;font-size:15px;line-height:1.4}.formkit-form[data-uid="8d653b97b6"] [data-group=dropdown] select:focus{outline:none}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes]{text-align:left;margin:0}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox]{margin-bottom:10px}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] *{cursor:pointer}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox]:last-of-type{margin-bottom:0}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] input[type=checkbox]{display:none}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] input[type=checkbox]+label:after{content:none}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] input[type=checkbox]:checked+label:after{content:"";border-color:#fff}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] input[type=checkbox]:checked+label:before{background:#10bf7a;border-color:#10bf7a}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] label{padding-left:28px;display:inline-block;position:relative}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] label:before,.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] label:after{content:"";display:inline-block;position:absolute}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] label:before{background:#fff;border:1px solid #e3e3e3;width:16px;height:16px;top:3px;left:0}.formkit-form[data-uid="8d653b97b6"] [data-group=checkboxes] [data-group=checkbox] label:after{border-bottom:2px solid #4d4d4d;border-left:2px solid #4d4d4d;width:8px;height:4px;top:8px;left:4px;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.formkit-form[data-uid="8d653b97b6"] .formkit-alert{text-align:center;background:#f9fafb;border:1px solid #e3e3e3;border-radius:5px;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;width:100%;margin:25px auto;padding:12px;list-style:none}.formkit-form[data-uid="8d653b97b6"] .formkit-alert:empty{display:none}.formkit-form[data-uid="8d653b97b6"] .formkit-alert-success{color:#0c905c;background:#d3fbeb;border-color:#10bf7a}.formkit-form[data-uid="8d653b97b6"] .formkit-alert-error{color:#ea4110;background:#fde8e2;border-color:#f2643b}.formkit-form[data-uid="8d653b97b6"] .formkit-spinner{text-align:center;width:0;height:0;margin:0 auto;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:absolute;top:0;left:0;right:0;overflow:hidden}.formkit-form[data-uid="8d653b97b6"] .formkit-spinner>div{opacity:.3;background-color:#fff;border-radius:100%;width:12px;height:12px;margin:auto;-webkit-animation:1.4s ease-in-out infinite both formkit-bouncedelay-formkit-form-data-uid-8d653b97b6-;animation:1.4s ease-in-out infinite both formkit-bouncedelay-formkit-form-data-uid-8d653b97b6-;display:inline-block}.formkit-form[data-uid="8d653b97b6"] .formkit-spinner>div:first-child{-webkit-animation-delay:-.32s;animation-delay:-.32s}.formkit-form[data-uid="8d653b97b6"] .formkit-spinner>div:nth-child(2){-webkit-animation-delay:-.16s;animation-delay:-.16s}.formkit-form[data-uid="8d653b97b6"] .formkit-submit[data-active] .formkit-spinner{opacity:1;width:50px;height:100%}.formkit-form[data-uid="8d653b97b6"] .formkit-submit[data-active] .formkit-spinner~span{opacity:0}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by[data-active=false]{opacity:.35}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit-container{z-index:5;width:100%;margin:10px 0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit-container[data-active=false]{opacity:.35}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit{color:#373f45;cursor:pointer;opacity:.95;text-indent:100%;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='%23373F45'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='%23373F45'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='%23373F45'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='%23373F45'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='%23373F45'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='%23373F45'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='%23373F45'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='%23373F45'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='%23373F45'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='%23373F45'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='%23373F45'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='%23373F45'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='%23373F45'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='%23373F45'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='%23373F45'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;border:1px solid #dde2e7;border-radius:4px;align-items:center;width:190px;height:36px;margin:0 auto;padding:0;-webkit-text-decoration:none;text-decoration:none;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:block;overflow:hidden}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit:hover,.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit:focus{opacity:1;background-color:#fff;-webkit-transform:scale(1.025)perspective(1px);-ms-transform:scale(1.025)perspective(1px);transform:scale(1.025)perspective(1px)}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit[data-variant=dark],.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit[data-variant=light]{background-color:#0000;border-color:#0000;width:166px}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit[data-variant=light]{color:#fff;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg width='162' height='20' viewBox='0 0 162 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M83.0561 15.2457C86.675 15.2457 89.4722 12.5154 89.4722 9.14749C89.4722 5.99211 86.8443 4.06563 85.1038 4.06563C82.6801 4.06563 80.7373 5.76407 80.4605 8.28551C80.4092 8.75244 80.0387 9.14403 79.5686 9.14069C78.7871 9.13509 77.6507 9.12841 76.9314 9.13092C76.6217 9.13199 76.3658 8.88106 76.381 8.57196C76.4895 6.38513 77.2218 4.3404 78.618 2.76974C80.1695 1.02445 82.4289 0 85.1038 0C89.5979 0 93.8406 4.07791 93.8406 9.14749C93.8406 14.7608 89.1832 19.3113 83.1517 19.3113C78.8502 19.3113 74.5179 16.5041 73.0053 12.5795C72.9999 12.565 72.9986 12.5492 73.0015 12.534C73.0218 12.4179 73.0617 12.3118 73.1011 12.2074C73.1583 12.0555 73.2143 11.907 73.2062 11.7359L73.18 11.1892C73.174 11.0569 73.2075 10.9258 73.2764 10.8127C73.3452 10.6995 73.4463 10.6094 73.5666 10.554L73.7852 10.4523C73.9077 10.3957 74.0148 10.3105 74.0976 10.204C74.1803 10.0974 74.2363 9.97252 74.2608 9.83983C74.3341 9.43894 74.6865 9.14749 75.0979 9.14749C75.7404 9.14749 76.299 9.57412 76.5088 10.1806C77.5188 13.1 79.1245 15.2457 83.0561 15.2457Z' fill='white'/%3E%3Cpath d='M155.758 6.91365C155.028 6.91365 154.804 6.47916 154.804 5.98857C154.804 5.46997 154.986 5.06348 155.758 5.06348C156.53 5.06348 156.712 5.46997 156.712 5.98857C156.712 6.47905 156.516 6.91365 155.758 6.91365ZM142.441 12.9304V9.32833L141.415 9.32323V8.90392C141.415 8.44719 141.786 8.07758 142.244 8.07986L142.441 8.08095V6.55306L144.082 6.09057V8.08073H145.569V8.50416C145.569 8.61242 145.548 8.71961 145.506 8.81961C145.465 8.91961 145.404 9.01047 145.328 9.08699C145.251 9.16351 145.16 9.2242 145.06 9.26559C144.96 9.30698 144.853 9.32826 144.745 9.32822H144.082V12.7201C144.082 13.2423 144.378 13.4256 144.76 13.4887C145.209 13.5629 145.583 13.888 145.583 14.343V14.9626C144.029 14.9626 142.441 14.8942 142.441 12.9304Z' fill='white'/%3E%3Cpath d='M110.058 7.92554C108.417 7.88344 106.396 8.92062 106.396 11.5137C106.396 14.0646 108.417 15.0738 110.058 15.0318C111.742 15.0738 113.748 14.0646 113.748 11.5137C113.748 8.92062 111.742 7.88344 110.058 7.92554ZM110.07 13.7586C108.878 13.7586 108.032 12.8905 108.032 11.461C108.032 10.1013 108.878 9.20569 110.071 9.20569C111.263 9.20569 112.101 10.0995 112.101 11.459C112.101 12.8887 111.263 13.7586 110.07 13.7586Z' fill='white'/%3E%3Cpath d='M118.06 7.94098C119.491 7.94098 120.978 8.33337 120.978 11.1366V14.893H120.063C119.608 14.893 119.238 14.524 119.238 14.0689V10.9965C119.238 9.66506 118.747 9.16047 117.891 9.16047C117.414 9.16047 116.797 9.52486 116.502 9.81915V14.069C116.502 14.1773 116.481 14.2845 116.44 14.3845C116.398 14.4845 116.337 14.5753 116.261 14.6519C116.184 14.7284 116.093 14.7891 115.993 14.8305C115.893 14.8719 115.786 14.8931 115.678 14.8931H114.847V8.10918H115.773C115.932 8.10914 116.087 8.16315 116.212 8.26242C116.337 8.36168 116.424 8.50033 116.46 8.65577C116.881 8.19328 117.428 7.94098 118.06 7.94098ZM122.854 8.09713C123.024 8.09708 123.19 8.1496 123.329 8.2475C123.468 8.34541 123.574 8.48391 123.631 8.64405L125.133 12.8486L126.635 8.64415C126.692 8.48402 126.798 8.34551 126.937 8.2476C127.076 8.1497 127.242 8.09718 127.412 8.09724H128.598L126.152 14.3567C126.091 14.5112 125.986 14.6439 125.849 14.7374C125.711 14.831 125.549 14.881 125.383 14.8809H124.333L121.668 8.09713H122.854Z' fill='white'/%3E%3Cpath d='M135.085 14.5514C134.566 14.7616 133.513 15.0416 132.418 15.0416C130.496 15.0416 129.024 13.9345 129.024 11.4396C129.024 9.19701 130.451 7.99792 132.191 7.99792C134.338 7.99792 135.254 9.4378 135.158 11.3979C135.139 11.8029 134.786 12.0983 134.38 12.0983H130.679C130.763 13.1916 131.562 13.7662 132.615 13.7662C133.028 13.7662 133.462 13.7452 133.983 13.6481C134.535 13.545 135.085 13.9375 135.085 14.4985V14.5514ZM133.673 10.949C133.785 9.87621 133.061 9.28752 132.191 9.28752C131.321 9.28752 130.734 9.93979 130.679 10.9489L133.673 10.949Z' fill='white'/%3E%3Cpath d='M137.345 8.11122C137.497 8.11118 137.645 8.16229 137.765 8.25635C137.884 8.35041 137.969 8.48197 138.005 8.62993C138.566 8.20932 139.268 7.94303 139.759 7.94303C139.801 7.94303 140.068 7.94303 140.489 7.99913V8.7265C140.489 9.11748 140.15 9.4147 139.759 9.4147C139.31 9.4147 138.651 9.5829 138.131 9.8773V14.8951H136.462V8.11112L137.345 8.11122ZM156.6 14.0508V8.09104H155.769C155.314 8.09104 154.944 8.45999 154.944 8.9151V14.8748H155.775C156.23 14.8748 156.6 14.5058 156.6 14.0508ZM158.857 12.9447V9.34254H157.749V8.91912C157.749 8.46401 158.118 8.09506 158.574 8.09506H158.857V6.56739L160.499 6.10479V8.09506H161.986V8.51848C161.986 8.97359 161.617 9.34254 161.161 9.34254H160.499V12.7345C160.499 13.2566 160.795 13.44 161.177 13.503C161.626 13.5774 162 13.9024 162 14.3574V14.977C160.446 14.977 158.857 14.9086 158.857 12.9447ZM98.1929 10.1124C98.2033 6.94046 100.598 5.16809 102.895 5.16809C104.171 5.16809 105.342 5.44285 106.304 6.12953L105.914 6.6631C105.654 7.02011 105.16 7.16194 104.749 6.99949C104.169 6.7702 103.622 6.7218 103.215 6.7218C101.335 6.7218 99.9169 7.92849 99.9068 10.1123C99.9169 12.2959 101.335 13.5201 103.215 13.5201C103.622 13.5201 104.169 13.4717 104.749 13.2424C105.16 13.0799 105.654 13.2046 105.914 13.5615L106.304 14.0952C105.342 14.7819 104.171 15.0566 102.895 15.0566C100.598 15.0566 98.2033 13.2842 98.1929 10.1124ZM147.619 5.21768C148.074 5.21768 148.444 5.58663 148.444 6.04174V9.81968L151.82 5.58131C151.897 5.47733 151.997 5.39282 152.112 5.3346C152.227 5.27638 152.355 5.24607 152.484 5.24611H153.984L150.166 10.0615L153.984 14.8749H152.484C152.355 14.8749 152.227 14.8446 152.112 14.7864C151.997 14.7281 151.897 14.6436 151.82 14.5397L148.444 10.3025V14.0508C148.444 14.5059 148.074 14.8749 147.619 14.8749H146.746V5.21768H147.619Z' fill='white'/%3E%3Cpath d='M0.773438 6.5752H2.68066C3.56543 6.5752 4.2041 6.7041 4.59668 6.96191C4.99219 7.21973 5.18994 7.62695 5.18994 8.18359C5.18994 8.55859 5.09326 8.87061 4.8999 9.11963C4.70654 9.36865 4.42822 9.52539 4.06494 9.58984V9.63379C4.51611 9.71875 4.84717 9.88721 5.05811 10.1392C5.27197 10.3882 5.37891 10.7266 5.37891 11.1543C5.37891 11.7314 5.17676 12.1841 4.77246 12.5122C4.37109 12.8374 3.81152 13 3.09375 13H0.773438V6.5752ZM1.82373 9.22949H2.83447C3.27393 9.22949 3.59473 9.16064 3.79688 9.02295C3.99902 8.88232 4.1001 8.64502 4.1001 8.31104C4.1001 8.00928 3.99023 7.79102 3.77051 7.65625C3.55371 7.52148 3.20801 7.4541 2.7334 7.4541H1.82373V9.22949ZM1.82373 10.082V12.1167H2.93994C3.37939 12.1167 3.71045 12.0332 3.93311 11.8662C4.15869 11.6963 4.27148 11.4297 4.27148 11.0664C4.27148 10.7324 4.15723 10.4849 3.92871 10.3237C3.7002 10.1626 3.35303 10.082 2.88721 10.082H1.82373Z' fill='white'/%3E%3Cpath d='M13.011 6.5752V10.7324C13.011 11.207 12.9084 11.623 12.7034 11.9805C12.5012 12.335 12.2068 12.6089 11.8201 12.8022C11.4363 12.9927 10.9763 13.0879 10.4402 13.0879C9.6433 13.0879 9.02368 12.877 8.5813 12.4551C8.13892 12.0332 7.91772 11.4531 7.91772 10.7148V6.5752H8.9724V10.6401C8.9724 11.1704 9.09546 11.5615 9.34155 11.8135C9.58765 12.0654 9.96557 12.1914 10.4753 12.1914C11.4656 12.1914 11.9607 11.6714 11.9607 10.6313V6.5752H13.011Z' fill='white'/%3E%3Cpath d='M15.9146 13V6.5752H16.9649V13H15.9146Z' fill='white'/%3E%3Cpath d='M19.9255 13V6.5752H20.9758V12.0991H23.696V13H19.9255Z' fill='white'/%3E%3Cpath d='M28.2828 13H27.2325V7.47607H25.3428V6.5752H30.1724V7.47607H28.2828V13Z' fill='white'/%3E%3Cpath d='M41.9472 13H40.8046L39.7148 9.16796C39.6679 9.00097 39.6093 8.76074 39.539 8.44727C39.4687 8.13086 39.4262 7.91113 39.4116 7.78809C39.3823 7.97559 39.3339 8.21875 39.2665 8.51758C39.2021 8.81641 39.1479 9.03905 39.1039 9.18554L38.0405 13H36.8979L36.0673 9.7832L35.2236 6.5752H36.2958L37.2143 10.3193C37.3578 10.9199 37.4604 11.4502 37.5219 11.9102C37.5541 11.6611 37.6025 11.3828 37.6669 11.0752C37.7314 10.7676 37.79 10.5186 37.8427 10.3281L38.8886 6.5752H39.9301L41.0024 10.3457C41.1049 10.6943 41.2133 11.2158 41.3276 11.9102C41.3715 11.4912 41.477 10.958 41.644 10.3105L42.558 6.5752H43.6215L41.9472 13Z' fill='white'/%3E%3Cpath d='M45.7957 13V6.5752H46.846V13H45.7957Z' fill='white'/%3E%3Cpath d='M52.0258 13H50.9755V7.47607H49.0859V6.5752H53.9155V7.47607H52.0258V13Z' fill='white'/%3E%3Cpath d='M61.2312 13H60.1765V10.104H57.2146V13H56.1643V6.5752H57.2146V9.20312H60.1765V6.5752H61.2312V13Z' fill='white'/%3E%3C/svg%3E")}@-webkit-keyframes formkit-bouncedelay-formkit-form-data-uid-8d653b97b6-{0%,80%,to{-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}40%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}@keyframes formkit-bouncedelay-formkit-form-data-uid-8d653b97b6-{0%,80%,to{-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}40%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.formkit-form[data-uid="8d653b97b6"] blockquote{border-left:5px solid #e1e1e1;margin:0 0 20px;padding:10px 20px}.formkit-form[data-uid="8d653b97b6"] .seva-custom-content{color:#fff;mix-blend-mode:difference;padding:15px;font-size:16px}.formkit-form[data-uid="8d653b97b6"]{max-width:700px}.formkit-form[data-uid="8d653b97b6"] [data-style=clean]{width:100%}.formkit-form[data-uid="8d653b97b6"] .formkit-fields{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0 auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.formkit-form[data-uid="8d653b97b6"] .formkit-field,.formkit-form[data-uid="8d653b97b6"] .formkit-submit{-webkit-flex:1 0 100%;-ms-flex:1 0 100%;flex:1 0 100%;margin:0 0 15px}.formkit-form[data-uid="8d653b97b6"] .formkit-powered-by-convertkit-container{margin:0}.formkit-form[data-uid="8d653b97b6"] .formkit-submit{position:static}.formkit-form[data-uid="8d653b97b6"][min-width~="700"] [data-style=clean],.formkit-form[data-uid="8d653b97b6"][min-width~="800"] [data-style=clean]{padding:10px}.formkit-form[data-uid="8d653b97b6"][min-width~="700"] .formkit-fields[data-stacked=false],.formkit-form[data-uid="8d653b97b6"][min-width~="800"] .formkit-fields[data-stacked=false]{margin-left:-5px;margin-right:-5px}.formkit-form[data-uid="8d653b97b6"][min-width~="700"] .formkit-fields[data-stacked=false] .formkit-field,.formkit-form[data-uid="8d653b97b6"][min-width~="800"] .formkit-fields[data-stacked=false] .formkit-field,.formkit-form[data-uid="8d653b97b6"][min-width~="700"] .formkit-fields[data-stacked=false] .formkit-submit,.formkit-form[data-uid="8d653b97b6"][min-width~="800"] .formkit-fields[data-stacked=false] .formkit-submit{margin:0 5px 15px}.formkit-form[data-uid="8d653b97b6"][min-width~="700"] .formkit-fields[data-stacked=false] .formkit-field,.formkit-form[data-uid="8d653b97b6"][min-width~="800"] .formkit-fields[data-stacked=false] .formkit-field{-webkit-flex:100 auto;-ms-flex:100 auto;flex:100 auto}.formkit-form[data-uid="8d653b97b6"][min-width~="700"] .formkit-fields[data-stacked=false] .formkit-submit,.formkit-form[data-uid="8d653b97b6"][min-width~="800"] .formkit-fields[data-stacked=false] .formkit-submit{-webkit-flex:auto;-ms-flex:auto;flex:auto}</style></form>
</div><div><div class="quoteContainer_Karu"><figure class="tweetQuote_h8Rz"><blockquote><a href="https://x.com/grabbou/status/1829126194022715617" target="_blank" rel="noreferrer nofollow">If every newsletter was as informative, the world would be a better place!</a></blockquote><figcaption><a href="https://twitter.com/grabbou" target="_blank" rel="noreferrer nofollow"><div class="avatar"><img alt="Mike Grabowski" class="avatar__photo shadow--md avatarImg_b51M" src="https://unavatar.io/twitter/grabbou?fallback=https://github.com/grabbou.png"><div class="avatar__intro"><strong class="avatar__name"><cite>Mike Grabowski</cite></strong><small class="avatar__subtitle" itemprop="description">CTO and founder - Callstack</small></div></div></a></figcaption></figure></div></div></div>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_JmGV" id="over-returning-hooks">Over-returning hooks<a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#over-returning-hooks" class="hash-link" aria-label="Direct link to Over-returning hooks" title="Direct link to Over-returning hooks">​</a></h2>
<p>Let's illustrate the problem with <a href="https://reactrouter.com/en/main/hooks/use-location" target="_blank" rel="noopener noreferrer"><code>useLocation()</code></a> from React-Router.</p>
<p>This hook returns an object with many attributes (<code>pathname</code>, <code>hash</code>, <code>search</code>...), but you might not read all of them. Just calling the hook will trigger re-renders when any of these attributes is updated.</p>
<p>Let's consider this app:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">CurrentPathname</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> pathname </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useLocation</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">pathname</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">CurrentHash</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> hash </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useLocation</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">hash</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Links</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">to</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">#link1</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">#link1</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">to</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">#link2</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">#link2</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">to</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">#link3</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text">#link3</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag class-name" style="color:#00009f">Link</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">App</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">CurrentPathname</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">CurrentHash</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag class-name" style="color:#00009f">Links</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain-text"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="browserWindow_my1Q"><div class="browserWindowHeader_jXSR"><div class="buttons_uHc7"><span class="dot_giz1" style="background:#f25f58"></span><span class="dot_giz1" style="background:#fbbe3c"></span><span class="dot_giz1" style="background:#58cb42"></span></div><div class="browserWindowAddressBar_Pd8y text--truncate">http://localhost:3000</div><div class="browserWindowMenuIcon_Vhuh"><div><span class="bar_rrRL"></span><span class="bar_rrRL"></span><span class="bar_rrRL"></span></div></div></div><div class="browserWindowBody_Idgs"><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">CurrentPathname</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem">/articles/useSyncExternalStore-the-underrated-react-api</div></div><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">CurrentHash</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem">undefined</div></div><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">Links</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem"><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link1">#link1</a><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link2" style="margin-left:2rem">#link2</a><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link3" style="margin-left:2rem">#link3</a></div></div></div></div>
<p>On any hash link click, the <code>CurrentPathname</code> component will re-render, even if it's not even using the <code>hash</code> attribute 😅.</p>
<div class="theme-admonition theme-admonition-tip admonition_WCGJ alert alert--success"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_pbrs"><p>Whenever a hook returns data that you don't display, think about React re-renders. If you don't pay attention, a tiny <code>useLocation()</code> call added at the top of a React tree could harm your app's performance.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_WCGJ alert alert--info"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_pbrs"><p>The goal is not to criticize React-Router, but rather to illustrate the problem. <code>useLocation()</code> is just a good pragmatic candidate to create this interactive article. Your own React hooks and other third-party libraries might also over-return.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_JmGV" id="usesyncexternalstore-to-the-rescue"><code>useSyncExternalStore</code> to the rescue?<a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#usesyncexternalstore-to-the-rescue" class="hash-link" aria-label="Direct link to usesyncexternalstore-to-the-rescue" title="Direct link to usesyncexternalstore-to-the-rescue">​</a></h2>
<p>The <a href="https://reactjs.org/docs/hooks-reference.html#usesyncexternalstore" target="_blank" rel="noopener noreferrer">official documentation</a> says:</p>
<blockquote>
<p>useSyncExternalStore is a hook recommended for reading and subscribing from external data sources in a way that’s compatible with concurrent rendering features like selective hydration and time slicing.
This method returns the value of the store and accepts three arguments:</p>
<ul>
<li><code>subscribe</code>: function to register a callback that is called whenever the store changes.</li>
<li><code>getSnapshot</code>: function that returns the current value of the store.</li>
<li><code>getServerSnapshot</code>: function that returns the snapshot used during server rendering.</li>
</ul>
</blockquote>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token generic-function function" style="color:#d73a49">useSyncExternalStore</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Snapshot</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">subscribe</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function-variable function" style="color:#d73a49">onStoreChange</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function-variable function" style="color:#d73a49">getSnapshot</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token maybe-class-name">Snapshot</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  getServerSnapshot</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token maybe-class-name">Snapshot</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">Snapshot</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This feels a bit abstract. This <a href="https://beta.reactjs.org/learn/you-might-not-need-an-effect#subscribing-to-an-external-store" target="_blank" rel="noopener noreferrer">beta doc page</a> gives a good example:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"online"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"offline"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">removeEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"online"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token dom variable" style="color:#36acaa">window</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">removeEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"offline"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> callback</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useOnlineStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSyncExternalStore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subscribe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">navigator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">onLine</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ChatIndicator</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> isOnline </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useOnlineStatus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>It turns out that the browser history can also be considered as an external data source. Let's see how to use <code>useSyncExternalStore</code> with React-Router!</p>
<h2 class="anchor anchorWithStickyNavbar_JmGV" id="implementing-usehistoryselector">Implementing <code>useHistorySelector()</code><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#implementing-usehistoryselector" class="hash-link" aria-label="Direct link to implementing-usehistoryselector" title="Direct link to implementing-usehistoryselector">​</a></h2>
<p>React-Router expose everything we need to wire <code>useSyncExternalStore</code>:</p>
<ul>
<li>access the browser history with <a href="https://v5.reactrouter.com/web/api/Hooks/usehistory" target="_blank" rel="noopener noreferrer"><code>useHistory()</code></a></li>
<li>subscribe for history updates with <a href="https://github.com/remix-run/history/blob/main/docs/api-reference.md#history.listen" target="_blank" rel="noopener noreferrer"><code>history.listen(callback)</code></a></li>
<li>access a snapshot of the current location with <a href="https://github.com/remix-run/history/blob/main/docs/api-reference.md#historylocation" target="_blank" rel="noopener noreferrer"><code>history.location</code></a></li>
</ul>
<div class="theme-admonition theme-admonition-caution admonition_WCGJ alert alert--warning"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>caution</div><div class="admonitionContent_pbrs"><p>This website uses React-Router v5: the solution will be different for React-Router v6 (<a href="https://twitter.com/Zh0uzi/status/1567523679604539405" target="_blank" rel="noopener noreferrer">see</a>).</p></div></div>
<p>The implementation of <code>useHistorySelector()</code> relatively simple:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useHistorySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">selector</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> history </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useHistory</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSyncExternalStore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">history</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">listen</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">selector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">history</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's use it in our app:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">CurrentPathname</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> pathname </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useHistorySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">history</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> history</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pathname</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">pathname</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">CurrentHash</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> hash </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useHistorySelector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">history</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> history</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">hash</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">hash</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="browserWindow_my1Q"><div class="browserWindowHeader_jXSR"><div class="buttons_uHc7"><span class="dot_giz1" style="background:#f25f58"></span><span class="dot_giz1" style="background:#fbbe3c"></span><span class="dot_giz1" style="background:#58cb42"></span></div><div class="browserWindowAddressBar_Pd8y text--truncate">http://localhost:3000</div><div class="browserWindowMenuIcon_Vhuh"><div><span class="bar_rrRL"></span><span class="bar_rrRL"></span><span class="bar_rrRL"></span></div></div></div><div class="browserWindowBody_Idgs"><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">CurrentPathname</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem"></div></div><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">CurrentHash</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem">undefined</div></div><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">Links</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem"><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link1">#link1</a><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link2" style="margin-left:2rem">#link2</a><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#link3" style="margin-left:2rem">#link3</a></div></div></div></div>
<p>Now, when you click on a hash link above, the <code>CurrentPathname</code> component will <strong>not re-render</strong> anymore!</p>
<h2 class="anchor anchorWithStickyNavbar_JmGV" id="another-example-scrolly">Another example: <code>scrollY</code><a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#another-example-scrolly" class="hash-link" aria-label="Direct link to another-example-scrolly" title="Direct link to another-example-scrolly">​</a></h2>
<p>There are so many external data sources that we can subscribe to, and implementing your own selector system on top might enable you to optimize React re-renders.</p>
<p>For example, let's consider we want to use the <code>scrollY</code> position of a page. We can implement this custom React hook:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// A memoized constant fn prevents unsubscribe/resubscribe</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// In practice it is not a big deal</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">onStoreChange</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  global</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">window</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"scroll"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> onStoreChange</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    global</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">window</span><span class="token operator" style="color:#393A34">?.</span><span class="token method function property-access" style="color:#d73a49">removeEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token string" style="color:#e3116c">"scroll"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      onStoreChange</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useScrollY</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function-variable function" style="color:#d73a49">selector</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useSyncExternalStore</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    subscribe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">selector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">global</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">window</span><span class="token operator" style="color:#393A34">?.</span><span class="token plain">scrollY</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can now use this hook with an optional selector:</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_D5yF"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_AclH"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ScrollY</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scrollY </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useScrollY</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">scrollY</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ScrollYFloored</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> to </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> scrollYFloored </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">useScrollY</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">y</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    y </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token known-class-name class-name">Math</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">floor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">y </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> to</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> to </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">scrollYFloored</span><span class="token punctuation" style="color:#393A34">}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_FoOz"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_L0B6"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="browserWindow_my1Q"><div class="browserWindowHeader_jXSR"><div class="buttons_uHc7"><span class="dot_giz1" style="background:#f25f58"></span><span class="dot_giz1" style="background:#fbbe3c"></span><span class="dot_giz1" style="background:#58cb42"></span></div><div class="browserWindowAddressBar_Pd8y text--truncate">http://localhost:3000</div><div class="browserWindowMenuIcon_Vhuh"><div><span class="bar_rrRL"></span><span class="bar_rrRL"></span><span class="bar_rrRL"></span></div></div></div><div class="browserWindowBody_Idgs"><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">ScrollY</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem">undefined</div></div><div class="renderBox_fyHl"><div><span class="renderTitle_KowX">ScrollY Floored</span><span class="rerender_TAh9">Render</span></div><div style="margin-top:0.5rem;padding:0.5rem">undefined</div></div></div></div>
<p>Scroll the page and see how the components above re-render? One is re-rendering less than the other!</p>
<div class="theme-admonition theme-admonition-info admonition_WCGJ alert alert--info"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_pbrs"><p>When you don't need a <code>scrollY</code> 1 pixel precision level, returning a wide range value such as <code>scrollY</code> can also be considered as over-returning. Consider returning a narrower value.</p><p>For example: a <code>useResponsiveBreakpoint()</code> hook that only returns a limited set of values (<code>small</code>, <code>medium</code> or <code>large</code>) will be more optimized than a <code>useViewportWidth()</code> hook.</p><p>If a React component only handles <code>large</code> screens differently, you can create an even narrower <code>useIsLargeScreen()</code> hook returning a boolean.</p></div></div>
<h2 class="anchor anchorWithStickyNavbar_JmGV" id="conclusion">Conclusion<a href="https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>I hope this article convinced you to take a second look at <code>useSyncExternalStore()</code>. I feel this hook is currently underused in the React ecosystem, and deserves a bit more attention. There are many external data sources that you can subscribe to.</p>
<p>If you still haven't upgraded to React 18, there's a npm <a href="https://www.npmjs.com/package/use-sync-external-store" target="_blank" rel="noopener noreferrer">use-sync-external-store</a> shim that you can already use today in older versions. There is also a <code>use-sync-external-store/with-selector</code> export in case you need to return a memoized non-primitive value.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Records & Tuples for React]]></title>
            <link>https://thisweekinreact.com/articles/records-and-tuples-for-react</link>
            <guid>https://thisweekinreact.com/articles/records-and-tuples-for-react</guid>
            <pubDate>Fri, 31 Jul 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[.Records & Tuples for React... and how they are much more than immutable data structures.]]></description>
            <content:encoded><![CDATA[<p><strong>Records &amp; Tuples</strong>, a very interesting <strong><a href="https://github.com/tc39/proposal-record-tuple" target="_blank" rel="noopener noreferrer">proposal</a></strong>, has just reached <strong><a href="https://twitter.com/robpalmer2/status/1286040041089904640" target="_blank" rel="noopener noreferrer">stage 2</a></strong> at <strong>TC39</strong>.</p>
<p>They bring <strong>deeply immutable data structures</strong> to JavaScript.</p>
<p>But don't overlook their <strong>equality properties</strong>, that are <u><strong>VERY</strong></u> interesting for <strong>React</strong>.</p>
<p>A whole category of <strong>React bugs</strong> are related to <strong>unstable object identities</strong>:</p>
<ul>
<li><strong>Performance</strong>: re-renders that could be avoided</li>
<li><strong>Behavior</strong>: useless effect re-executions, infinite loops</li>
<li><strong>API surface</strong>: unability to express when a stable object identity matters</li>
</ul>
<p>I will explain the basics of <strong>Records &amp; Tuples</strong>, and how they can solve <strong>real world React issues</strong>.</p>
<p><a href="https://sebastienlorber.com/records-and-tuples-for-react" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="hero" src="https://thisweekinreact.com/assets/images/hero-001c6a6b3ce8665c9c70243a596bb5a5.png" width="1200" height="630" class="img_SS3x"></a></p>
<p>🔗 <a href="https://sebastienlorber.com/records-and-tuples-for-react" target="_blank" rel="noopener noreferrer"><strong>Read More</strong></a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Expo in Gatsby]]></title>
            <link>https://thisweekinreact.com/articles/using-expo-in-gatsby</link>
            <guid>https://thisweekinreact.com/articles/using-expo-in-gatsby</guid>
            <pubDate>Mon, 11 May 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Using Expo in Gatsby... or how to use cross-platform components in a MDX blog post]]></description>
            <content:encoded><![CDATA[<p>You probably heard of <a href="https://github.com/necolas/react-native-web" target="_blank" rel="noopener noreferrer">React-Native-Web</a>, allowing to render <strong>React-Native views on the web</strong>.</p>
<p><strong>So, what about using React-Native in a Gatsby website?</strong></p>
<p>This post is a <strong>proof-of-concept</strong>: it contains <strong>React-Native</strong> and <strong>Expo</strong> interactive components, embedded directly into <a href="https://github.com/slorber/sebastienlorber.com/tree/master/content/posts/2020-05-11-using-expo-in-gatsby" target="_blank" rel="noopener noreferrer">this article</a> (using <a href="https://github.com/mdx-js/mdx" target="_blank" rel="noopener noreferrer">MDX</a>), of my <a href="https://github.com/slorber/sebastienlorber.com" target="_blank" rel="noopener noreferrer">open-source</a> Gatsby site.</p>
<p><a href="https://sebastienlorber.com/using-expo-in-gatsby" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="hero" src="https://thisweekinreact.com/assets/images/hero-b6045c6b11d5ff8c8364c72e32261e82.png" width="1600" height="800" class="img_SS3x"></a></p>
<p>🔗 <a href="https://sebastienlorber.com/using-expo-in-gatsby" target="_blank" rel="noopener noreferrer"><strong>Read More</strong></a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Atomic CSS-in-JS]]></title>
            <link>https://thisweekinreact.com/articles/atomic-css-in-js</link>
            <guid>https://thisweekinreact.com/articles/atomic-css-in-js</guid>
            <pubDate>Mon, 27 Apr 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Atomic CSS-in-JS... or how to scale your CSS-in-JS.]]></description>
            <content:encoded><![CDATA[<p>With recent production deployments from Facebook and Twitter, I think a new trend is slowly growing: atomic CSS-in-JS.</p>
<p>In this post, we'll see what atomic CSS is, how it relates to functional / utility-first CSS like TailwindCSS, and that big players are adopting it in their modern React codebases.</p>
<p>As I'm not a expert of this subject, don't expect a deep dive about the pros and cons. I just hope you get an idea about what it's about.</p>
<p><strong>Note</strong>: Atomic CSS is not really related to <a href="https://atomicdesign.bradfrost.com/" target="_blank" rel="noopener noreferrer">Atomic Design</a>.</p>
<p><a href="https://sebastienlorber.com/atomic-css-in-js" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="hero" src="https://thisweekinreact.com/assets/images/hero-c191a7d6ae76d75f1c7372c89d9fdd79.png" width="1200" height="630" class="img_SS3x"></a></p>
<p>🔗 <a href="https://sebastienlorber.com/atomic-css-in-js" target="_blank" rel="noopener noreferrer"><strong>Read More</strong></a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Handling API request race conditions in React]]></title>
            <link>https://thisweekinreact.com/articles/handling-api-request-race-conditions-in-react</link>
            <guid>https://thisweekinreact.com/articles/handling-api-request-race-conditions-in-react</guid>
            <pubDate>Fri, 30 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Handling API request race conditions in React... or how to avoid rendering the wrong data]]></description>
            <content:encoded><![CDATA[<p>Many blog articles talk about loading api/async data in React apps, with <code>componentDidMount</code>, <code>useEffect</code>, Redux, Apollo...</p>
<p>Yet, all those articles are <strong>generally optimistic</strong>, and never mention something important to consider: race conditions could happen, and your UI may end up in an <strong>inconsistent state</strong>.</p>
<p><a href="https://sebastienlorber.com/handling-api-request-race-conditions-in-react" target="_blank" rel="noopener noreferrer"><img decoding="async" loading="lazy" alt="hero" src="https://thisweekinreact.com/assets/images/hero-df60db3161793a5f4ea7712b4c74ea55.png" width="1722" height="754" class="img_SS3x"></a></p>
<p>🔗 <a href="https://sebastienlorber.com/handling-api-request-race-conditions-in-react" target="_blank" rel="noopener noreferrer"><strong>Read More</strong></a></p>]]></content:encoded>
        </item>
    </channel>
</rss>