<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ZHANGYU</title>
    <description>The latest articles on Forem by ZHANGYU (@zhangyu1818).</description>
    <link>https://forem.com/zhangyu1818</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1182138%2Ffcf8468e-d753-4299-83d1-006c373917c8.jpeg</url>
      <title>Forem: ZHANGYU</title>
      <link>https://forem.com/zhangyu1818</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zhangyu1818"/>
    <language>en</language>
    <item>
      <title>I wrote a new blog using Next.js App router</title>
      <dc:creator>ZHANGYU</dc:creator>
      <pubDate>Thu, 16 May 2024 16:11:07 +0000</pubDate>
      <link>https://forem.com/zhangyu1818/i-wrote-a-new-blog-using-nextjs-app-router-1kl7</link>
      <guid>https://forem.com/zhangyu1818/i-wrote-a-new-blog-using-nextjs-app-router-1kl7</guid>
      <description>&lt;p&gt;Before I dive into the development journey of my new blog, you might want to check it out first at &lt;a href="https://zhangyu.dev"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Back in 2020, React introduced &lt;a href="https://legacy.reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;&lt;strong&gt;Server Components&lt;/strong&gt;&lt;/a&gt;. I was amazed by the possibility of writing asynchronous components.&lt;/p&gt;

&lt;p&gt;Writing async components isn't groundbreaking per se; there was a short-lived framework before that used JSX syntax and allowed async components even on the client side.&lt;/p&gt;

&lt;p&gt;What was novel, however, was React's support for async components, even though they could only run on the server. At that time, there wasn't a stable framework to leverage this feature. By coincidence, a new project last year required using &lt;code&gt;Next.js&lt;/code&gt;. On my recommendation, we adopted the official &lt;code&gt;App Router&lt;/code&gt;, seamlessly integrating &lt;strong&gt;React Server Components&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To master &lt;strong&gt;React Server Components&lt;/strong&gt;, I decided to rewrite my blog using the &lt;code&gt;App Router&lt;/code&gt;. Previously, my blog was built with &lt;code&gt;Astro&lt;/code&gt;. Here’s a &lt;a href="https://blog-git-astro-v3-723156735.vercel.app/"&gt;preview of the old blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My requirements for the new blog were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fully utilize the &lt;code&gt;App Router&lt;/code&gt; and &lt;strong&gt;Server Components&lt;/strong&gt; to optimize performance.&lt;/li&gt;
&lt;li&gt;Adopt the latest and cutting-edge technologies.&lt;/li&gt;
&lt;li&gt;No backend services.&lt;/li&gt;
&lt;li&gt;Make it as visually appealing as possible.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Regarding the first point, &lt;strong&gt;Server Components&lt;/strong&gt; performed admirably.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--etyt0-pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.jsdelivr.net/gh/zhangyu1818/blog%40files/files/image-20240516231706718.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--etyt0-pe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.jsdelivr.net/gh/zhangyu1818/blog%40files/files/image-20240516231706718.png" alt="image-20240516231706718" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the second point, I am currently using:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt; — Needs no introduction.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react-spectrum.adobe.com/react-aria/components.html"&gt;React Aria Components&lt;/a&gt; — Not &lt;code&gt;shadcn/ui&lt;/code&gt;, nor &lt;code&gt;radix-ui&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tabler.io/icons"&gt;@tabler/icons-react&lt;/a&gt; — Over 5k icons, simply astonishing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://shiki.style/"&gt;shiki&lt;/a&gt; — Updated, more powerful syntax highlighting.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mdxjs.com/"&gt;MDX&lt;/a&gt; — Write &lt;code&gt;React&lt;/code&gt; code within Markdown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The highlights are &lt;code&gt;MDX&lt;/code&gt; and &lt;code&gt;shiki&lt;/code&gt;. I aim to include as many code examples as possible in my posts, allowing readers to interact with them. &lt;code&gt;shiki&lt;/code&gt; supports numerous &lt;a href="https://shiki.style/packages/transformers"&gt;plugins&lt;/a&gt; like &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;focus&lt;/code&gt;, &lt;code&gt;highlight&lt;/code&gt;, and the best one is &lt;a href="https://shikijs.github.io/twoslash/"&gt;&lt;code&gt;twoslash&lt;/code&gt;&lt;/a&gt;, which makes code blocks more user-friendly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MDX&lt;/code&gt; and &lt;code&gt;shiki&lt;/code&gt; are a match made in heaven. All these effects can run server-side without bundling any &lt;code&gt;js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the third point, I employed a novel approach:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using GitHub Discussions as the Blog Backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I haven’t seen anyone else using this method. I find it more blog-friendly than using &lt;strong&gt;GitHub Issues&lt;/strong&gt;. It has several distinct advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Permissions Management — Only the author can post content; others can only comment (unlike &lt;strong&gt;GitHub Issues&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Categories — &lt;strong&gt;GitHub Discussions&lt;/strong&gt; allows multiple categories (again, unlike &lt;strong&gt;GitHub Issues&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Tags — Customizable tags for posts with adjustable colors.&lt;/li&gt;
&lt;li&gt;Image Uploads — Pasting an image in the &lt;code&gt;Discussions&lt;/code&gt; input box uploads it to GitHub automatically.&lt;/li&gt;
&lt;li&gt;Comments — Complete commenting system from GitHub, including likes, replies, and mentions (with slight differences between &lt;strong&gt;Discussions&lt;/strong&gt; and &lt;strong&gt;Issues&lt;/strong&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moreover, &lt;strong&gt;GitHub&lt;/strong&gt; provides a robust &lt;code&gt;GraphQL API&lt;/code&gt;, enabling blog development with any front-end technology, even a console app.&lt;/p&gt;

&lt;p&gt;For the fourth point:&lt;/p&gt;

&lt;p&gt;I studied &lt;strong&gt;Bento&lt;/strong&gt; design on &lt;em&gt;Dribbble&lt;/em&gt;, drawing inspiration from various Bento-style blogs.&lt;/p&gt;

&lt;p&gt;Current missing features in my blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RSS feed&lt;/li&gt;
&lt;li&gt;Animations&lt;/li&gt;
&lt;li&gt;More interesting Bento sections&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shiki&lt;/code&gt; and &lt;code&gt;twoslash&lt;/code&gt; styles&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you previewed my &lt;a href="https://zhangyu.dev"&gt;blog&lt;/a&gt; and found it appealing, you can visit my &lt;a href="https://github.com/zhangyu1818/blog/issues"&gt;GitHub repository&lt;/a&gt;. It supports one-click deployment and includes a simple forking tutorial.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>blog</category>
    </item>
    <item>
      <title>The Principles Behind Front-end Routing</title>
      <dc:creator>ZHANGYU</dc:creator>
      <pubDate>Tue, 17 Oct 2023 07:05:51 +0000</pubDate>
      <link>https://forem.com/zhangyu1818/the-principles-behind-front-end-routing-4df4</link>
      <guid>https://forem.com/zhangyu1818/the-principles-behind-front-end-routing-4df4</guid>
      <description>&lt;p&gt;&lt;small&gt;Read on my &lt;a href="https://www.zhangyu.dev/post/128/"&gt;blog&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;




&lt;p&gt;Libraries like &lt;code&gt;react-router&lt;/code&gt; fundamentally depend on a package called &lt;code&gt;history&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;history&lt;/code&gt; is essentially a wrapper for the native &lt;code&gt;window.history&lt;/code&gt; API.&lt;/p&gt;

&lt;h2&gt;
  
  
  window.history API
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;window.history&lt;/code&gt; provides five methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;go&lt;/code&gt;: Navigate to a specific page; the parameter is a number. &lt;code&gt;go(1)&lt;/code&gt; goes forward one page, &lt;code&gt;go(-1)&lt;/code&gt; goes back one page.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;back&lt;/code&gt;: Equivalent to &lt;code&gt;go(-1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forward&lt;/code&gt;: Equivalent to &lt;code&gt;go(1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pushState&lt;/code&gt;: Adds a new history record.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;replaceState&lt;/code&gt;: Replaces the current history record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We mainly use &lt;code&gt;pushState&lt;/code&gt; and &lt;code&gt;replaceState&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  pushState
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;pushState&lt;/code&gt; method takes three arguments.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first argument is the &lt;code&gt;state&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;The second argument is the title, which is currently unused by the browser. To future-proof your code, it's advisable to pass an empty string here.&lt;/li&gt;
&lt;li&gt;The third argument is &lt;code&gt;url&lt;/code&gt;, which is displayed in the browser's address bar in real-time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The state object can be accessed via &lt;code&gt;window.history.state&lt;/code&gt; and defaults to &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To demonstrate, open the browser's console on the current page and type &lt;code&gt;window.history.pushState({state:0},"","/page")&lt;/code&gt;. You'll notice the browser address changes to &lt;code&gt;/page&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;window.history.state&lt;/code&gt; in the console; you'll see &lt;code&gt;{state: 0}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;window.history.back()&lt;/code&gt; to go back a page.&lt;/p&gt;

&lt;h3&gt;
  
  
  replaceState
&lt;/h3&gt;

&lt;p&gt;The key difference between &lt;code&gt;replaceState&lt;/code&gt; and &lt;code&gt;pushState&lt;/code&gt; is that &lt;code&gt;replaceState&lt;/code&gt; replaces the current history record.&lt;/p&gt;

&lt;p&gt;Open your console and type &lt;code&gt;window.history.replaceState({state:1},"","/replace")&lt;/code&gt;. You'll notice the browser address changes to &lt;code&gt;/replace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;window.history.state&lt;/code&gt; in the console to retrieve the current &lt;code&gt;{state: 1}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;window.history.back()&lt;/code&gt; to navigate to the previous page because the last one was replaced by us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking History Changes
&lt;/h3&gt;

&lt;p&gt;The browser provides a &lt;code&gt;popstate&lt;/code&gt; event to listen to history changes. However, this cannot track changes made by &lt;code&gt;pushState&lt;/code&gt; or &lt;code&gt;replaceState&lt;/code&gt;, nor can it determine the direction of navigation (forward or backward). It tracks only changes via &lt;code&gt;go&lt;/code&gt;, &lt;code&gt;back&lt;/code&gt;, &lt;code&gt;forward&lt;/code&gt;, and browser navigation buttons.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;popstate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Brief Dive into history's Source Code
&lt;/h2&gt;

&lt;p&gt;The history library solves the limitations of native listeners. It unifies these various APIs into a single &lt;code&gt;history&lt;/code&gt; object and independently implements listener functionality. When calling &lt;code&gt;push&lt;/code&gt; or &lt;code&gt;replace&lt;/code&gt;, it triggers the associated event callback functions and passes in the direction of navigation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// createBrowserHistory&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;globalHistory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Call it own listeners in the native popstate event&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handlePop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nextAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nextIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextLocation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getIndexAndLocation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="c1"&gt;// Call it own listeners&lt;/span&gt;
   &lt;span class="nx"&gt;applyTx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popstate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handlePop&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pop&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getIndexAndLocation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;listeners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createEvents&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Listener&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Call it own listeners&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;applyTx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextAction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextLocation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nx"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;To&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nextAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Push&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nextLocation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getNextLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;historyState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getHistoryStateAndUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextLocation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;globalHistory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;historyState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Call listeners when push&lt;/span&gt;
   &lt;span class="nx"&gt;applyTx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice that it merely creates its own &lt;code&gt;listeners&lt;/code&gt; array and manually invokes them during &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;replace&lt;/code&gt;, thereby addressing the issues of native APIs not triggering these events.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;createHashHistory&lt;/code&gt; is almost identical to &lt;code&gt;createBrowserHistory&lt;/code&gt;, but it additionally listens for &lt;code&gt;hashchange&lt;/code&gt; events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing React Router from Scratch
&lt;/h2&gt;

&lt;p&gt;Based on these principles, we can already write a simple router.&lt;/p&gt;

&lt;p&gt;Below is a straightforward 20-line implementation example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBrowserHistory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;history&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createBrowserHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;useLayoutEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/page1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;index&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/page1"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;historyRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;page1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In essence, different &lt;code&gt;pathname&lt;/code&gt; are used to display different elements. However, &lt;code&gt;react-router&lt;/code&gt; includes more complex conditions and logic. A more detailed analysis of its source code will be published soon.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;This post was originally published on December 22, 2021, and was written in Chinese. As I'm currently improving my English skills, I decided to translate one of my shorter posts. You can expect more content in English from me in the future.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
  </channel>
</rss>
