<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Crane</title>
  <subtitle>A UI builder.</subtitle>
  <link href="https://stonegate.me/feed/feed.xml" rel="self" />
  <link href="https://stonegate.me/" />
  <updated>2025-02-06T00:00:00Z</updated>
  <id>https://stonegate.me/</id>
  <author>
    <name>Stone</name>
  </author>
  <entry>
    <title>乙巳春节小记</title>
    <link href="https://stonegate.me/posts/2025-spring-festival-holiday/" />
    <updated>2025-02-06T00:00:00Z</updated>
    <id>https://stonegate.me/posts/2025-spring-festival-holiday/</id>
    <content type="html">&lt;p&gt;这篇小记记录下这个春节假期做了些什么。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;线上课程&lt;/h2&gt;
&lt;p&gt;这个假期完成了 &lt;a href=&quot;https://animations.dev&quot;&gt;animations.dev&lt;/a&gt; 的课程，这份课程是假期之前付钱买的，这个是我付费的第二个线上教程，之前是 &lt;a href=&quot;https://justjavascript.com/&quot;&gt;Just Javascript&lt;/a&gt; 。总体收获还是蛮大的，之前就对页面动画还有兴趣，只是一直没有很清晰的认识，只是偶尔用用 &lt;code&gt;gsap&lt;/code&gt;。这一次终于有了比较全面的认识，之后就是在项目中多练手了，入门成功。&lt;/p&gt;
&lt;h2 id=&quot;ui&quot;&gt;UI 升级&lt;/h2&gt;
&lt;p&gt;把 Crane 和 &lt;a href=&quot;https://docket.space&quot;&gt;Docket&lt;/a&gt; 的 UI 都做了升级，灵感来自于之前看到的新粗野主义设计风格，整体使用更为鲜艳的色彩，更跳跃的字体，感觉自己的设计水平有所提升。其他升级包括：个人网页升级到了 &lt;code&gt;eleventy v3.0&lt;/code&gt; ， Docket 部署切换到 Dokploy。&lt;/p&gt;
&lt;image-compare id=&quot;webc-_xD7d&quot; aria-label=&quot;Compare two images&quot; class=&quot;wxkaabajb&quot;&gt;
	&lt;div class=&quot;slider&quot;&gt;
		&lt;label for=&quot;webc-_xD7d-slider&quot; class=&quot;visually-hidden&quot;&gt;&lt;/label&gt;
		&lt;input type=&quot;range&quot; name=&quot;range-enabled&quot; value=&quot;50&quot; aria-controls=&quot;webc-_xD7d&quot; id=&quot;webc-_xD7d-slider&quot;&gt;
	&lt;/div&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/J5Cu9kWaDI-2539.avif 2539w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/J5Cu9kWaDI-2539.webp 2539w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/J5Cu9kWaDI-2539.jpeg&quot; alt=&quot;Docket new&quot; width=&quot;2539&quot; height=&quot;1280&quot;&gt;&lt;/picture&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/suS1u-OTHF-2539.avif 2539w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/suS1u-OTHF-2539.webp 2539w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/suS1u-OTHF-2539.jpeg&quot; alt=&quot;Docket old&quot; width=&quot;2539&quot; height=&quot;1280&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;/image-compare&gt;
&lt;h2 id=&quot;-2&quot;&gt;读书&lt;/h2&gt;
&lt;p&gt;读完了两本书，分别是许宏老师的《最早的帝国-二里岗文明冲击波》以及《印加帝国的末日》。这个假期尤其沉迷于石峁、二里头、二里岗、殷墟这段至今依旧神秘的夏商时代，即使已经有大量的考古发现，但是这段历史似乎还是在迷雾之中，每一座城都有着自己的特色，连殷和商这两个字都是谜团，二里岗文明最大的特色是辐射范围很大，推测此时的商应该是很强大的，可是殷墟的整体风格却和二里岗大不同，出现了甲骨文、马车这些跨时代的产物，同样是商，可是考古发现却似乎是两个政权。《印加帝国的末日》是一本读起来非常非常悲痛的书，168 个西班牙人征服和毁灭了一个辉煌的文明，无数的印第安人惨死，伟大的神庙被焚毁，尊贵的君主死于非命，这样的悲剧真是不忍卒读。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/4aEA1M-LNi-500.avif 500w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/4aEA1M-LNi-500.webp 500w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/2025-spring-festival-holiday/4aEA1M-LNi-500.jpeg&quot; alt=&quot;&quot; width=&quot;500&quot; height=&quot;451&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;-3&quot;&gt;观影&lt;/h2&gt;
&lt;p&gt;看了两部剧，《百年孤独》和《照明商店》，均非常推荐。&lt;/p&gt;
&lt;h2 id=&quot;-4&quot;&gt;语言&lt;/h2&gt;
&lt;p&gt;看了一部分 Haskell 的 &lt;a href=&quot;https://learnyouahaskell.github.io/chapters.html&quot;&gt;文档&lt;/a&gt;，入门太难，仅此而已。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>TradingView Advanced Chart 开发入门</title>
    <link href="https://stonegate.me/posts/tradingview-advanced-chart/" />
    <updated>2025-01-14T00:00:00Z</updated>
    <id>https://stonegate.me/posts/tradingview-advanced-chart/</id>
    <content type="html">&lt;p&gt;本文介绍的是在 Web 项目中接入 TradingView Advanced Chart 。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;申请&lt;/h2&gt;
&lt;p&gt;TradingView Advanced Chart 是免费使用的，代码文件需要通过 &lt;a href=&quot;https://www.tradingview.com/advanced-charts/&quot;&gt;官网&lt;/a&gt; 进行申请，申请的时候需要使用公司邮箱，申请后一周内会收到邮件回复，按照邮件内容填写并签署协议文件后回复即可，注意协议文件中邮箱要与申请邮箱保持一致。&lt;/p&gt;
&lt;h2 id=&quot;-2&quot;&gt;使用&lt;/h2&gt;
&lt;p&gt;使用 TradingView widget 分三步。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一步：
从项目仓库 &lt;a href=&quot;https://github.com/tradingview/charting_library/tree/master/charting_library&quot;&gt;下载&lt;/a&gt; ，并放到项目公开目录，一般是 &lt;code&gt;public&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;第二步：
在 DOM 中插入 &lt;code&gt;&amp;lt;div id=&amp;quot;tv_chart_container&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第三步：
初始化 &lt;code&gt;tvWidget&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tvWidget &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TradingView&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;library_path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;path_to_charting_library&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;tv-chart-container&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;autosize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;interval&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1 minute&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;favorites&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;intervals&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;15&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1D&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;allow_symbol_change&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;light&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;EXCHANGE:BTC/USDT&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// default pair&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Intl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;DateTimeFormat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolvedOptions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;timeZone&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;disabled_features&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;enabled_features&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token literal-property property&quot;&gt;custom_themes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;token literal-property property&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;datafeed&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;autosize&lt;/code&gt; 设置为 &lt;code&gt;true&lt;/code&gt; , 可以让 widget 始终占满父容器大小，这样只需要定义父容器样式就可以了。
&lt;code&gt;timiezone&lt;/code&gt; 设置 &lt;code&gt;Intl.DateTimeFormat().resolvedOptions().timeZone&lt;/code&gt; , 可以在界面上按用户时区显示时间。
&lt;code&gt;disabled_features&lt;/code&gt; 和 &lt;code&gt;enabled_features&lt;/code&gt; 用于选择功能，当你需要隐藏某些功能时，就需要在这里配置，功能列表具体可参考 &lt;a href=&quot;https://www.tradingview.com/charting-library-docs/latest/customization/Featuresets&quot;&gt;文档链接&lt;/a&gt; 。我自己的配置如下：&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;disabled_features&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;symbol_search_hot_key&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_quick_search&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_symbol_search&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_compare&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_settings&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_undo_redo&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;header_saveload&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;items_favoriting&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;symbol_search_hot_key&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;symbol_info&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;edit_buttons_in_legend&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;delete_button_in_legend&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;use_localstorage_for_settings&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;create_volume_indicator_by_default&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&#39;popup_hints&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;enabled_features&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;show_interval_dialog_on_key_press&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;items_favoriting&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以参考下图获取 UI 关键字：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/tradingview-advanced-chart/eY04nst0LV-1865.avif 1865w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/tradingview-advanced-chart/eY04nst0LV-1865.webp 1865w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/tradingview-advanced-chart/eY04nst0LV-1865.png&quot; alt=&quot;&quot; width=&quot;1865&quot; height=&quot;1438&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;custom_themes&lt;/code&gt;  用于设置主题，一般需要定义 &lt;code&gt;light&lt;/code&gt; 和 &lt;code&gt;dark&lt;/code&gt; 主题。
主题包括 &lt;code&gt;color1&lt;/code&gt; &lt;code&gt;color2&lt;/code&gt; &lt;code&gt;color3&lt;/code&gt; &lt;code&gt;color4&lt;/code&gt; &lt;code&gt;color5&lt;/code&gt; &lt;code&gt;color6&lt;/code&gt; &lt;code&gt;color7&lt;/code&gt; &lt;code&gt;white&lt;/code&gt; &lt;code&gt;black&lt;/code&gt; 九个颜色，其中 &lt;code&gt;color1&lt;/code&gt; 是主题色，&lt;code&gt;color3&lt;/code&gt; 是红色，&lt;code&gt;color4&lt;/code&gt; 是绿色。 你可以在 &lt;a href=&quot;https://codepen.io/tradingview/pen/abgzyBW&quot;&gt;这里&lt;/a&gt; 设置好主题，然后复制到项目中。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/tradingview-advanced-chart/2r6NERAn3a-1459.avif 1459w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/tradingview-advanced-chart/2r6NERAn3a-1459.webp 1459w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/tradingview-advanced-chart/2r6NERAn3a-1459.png&quot; alt=&quot;&quot; width=&quot;1459&quot; height=&quot;774&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;剩余一个配置就是 &lt;code&gt;datafeed&lt;/code&gt; ，这个也是最主要的配置，&lt;code&gt;datafeed&lt;/code&gt; 主要提供以下方法。&lt;a href=&quot;https://www.tradingview.com/charting-library-docs/latest/connecting_data/datafeed-api/required-methods/#onready&quot;&gt;文档链接&lt;/a&gt; .&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Datafeed&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;onReady&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; OnReadyCallback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;searchSymbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      userInput&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      exchange&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      symbolType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onResult&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SearchSymbolsCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;resolveSymbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      symbolName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onResolve&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ResolveCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DatafeedErrorCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      extension&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SymbolResolveExtension&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getBars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      symbolInfo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LibrarySymbolInfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resolution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ResolutionString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      periodParams&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; PeriodParams&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onResult&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HistoryCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DatafeedErrorCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;subscribeBars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      symbolInfo&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; LibrarySymbolInfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      resolution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ResolutionString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      onTick&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; SubscribeBarsCallback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      listenerGuid&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	  &lt;span class=&quot;token function-variable function&quot;&gt;onResetCacheNeededCallback&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;unsubscribeBars&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;subscriberUID&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;onReady&lt;/code&gt; 图表初始化完成时会调用此方法。&lt;code&gt;callback&lt;/code&gt; 可以调用一些基础配置。
&lt;code&gt;searchSymbol&lt;/code&gt; 用于按用户输入搜索代币。
&lt;code&gt;resolveSymboll&lt;/code&gt; 用户获取代币信息。&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; symbolInfo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;ticker&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BTCUSD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;BTCUSD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Bitcoin/USD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; symbolItem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;24x7&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Etc/UTC&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;exchange&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Example Exchange&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;minmov&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;pricescale&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;has_intraday&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;visible_plots_set&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;ohlcv&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;has_weekly_and_monthly&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;supported_resolutions&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;1&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;5&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;30&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;60&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1D&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;1W&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;volume_precision&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;data_status&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;streaming&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getBars&lt;/code&gt; 用于获取历史数据。
&lt;code&gt;subscribeBars&lt;/code&gt; 用于更新最新数据。
&lt;code&gt;unsubscribeBars&lt;/code&gt; 图表切换代币时会调用此方法。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My 2024 Review</title>
    <link href="https://stonegate.me/posts/my-2024-review/" />
    <updated>2025-01-01T00:00:00Z</updated>
    <id>https://stonegate.me/posts/my-2024-review/</id>
    <content type="html">&lt;h2 id=&quot;2024&quot;&gt;2024 年度回顾&lt;/h2&gt;
&lt;p&gt;2024 是不平静的一年。也是希望萌芽的一年。万物复苏，希望 2025 多一些希望，而不是绝望。&lt;/p&gt;
&lt;h2 id=&quot;code&quot;&gt;CODE&lt;/h2&gt;
&lt;p&gt;今天工作中技术上的转变包括从 &lt;code&gt;Nuxtjs v2&lt;/code&gt; 全面升级到 &lt;code&gt;Nuxtjs v3&lt;/code&gt;，UI 组件也切换到了 &lt;code&gt;Nuxt UI&lt;/code&gt; ，css 使用 &lt;code&gt;tailwindcss&lt;/code&gt; ，开发体验的提升是显而易见的。同时也有学习开发 &lt;code&gt;Nuxt Module&lt;/code&gt; .&lt;/p&gt;
&lt;p&gt;个人开发中，编辑器终于切换到了 &lt;code&gt;nvim&lt;/code&gt; ，终端使用 &lt;code&gt;kitty&lt;/code&gt; 。经过一段时间的配置，用起来都很顺手了，感谢 &lt;code&gt;avante.nvim&lt;/code&gt; , AI 用的也渐渐多起来了，尤其是最近一段时间，深深感受到 AI 的影响之大，要学习把 80% 的工作交给 AI 完成。最近做了一个小项目，叫作 &lt;code&gt;commits-assitant&lt;/code&gt;，大部分代码是通过 AI 完成的，通过 &lt;code&gt;git hooks&lt;/code&gt; 把提交的 &lt;code&gt;commits&lt;/code&gt; 存下来，然后可以再用 AI 分析总结，当然还有生成 commit 信息的功能，AI 的出现让开发这些小工具变得很容易，这样更容易 DIY 满足自己的需求。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;生活&lt;/h2&gt;
&lt;p&gt;在深夜心烦无人的时候，关灯躺着，静静的看一部老电影，慢慢变成了一个习惯，终于有机会慢慢看完了小津还有黑泽明的老电影。感谢《幕府将军》，让我可以慢慢认识日本的战国时代，看多好多好多日本剑戟片，认识了好多导演，五社英雄，小林正树，还有那个时代的风云人物，以前想了解日本历史总是不得其门，这次终于把轮廓研究清楚了。最推荐的也是最喜欢的其中一部是 《夺命剑》，就像最好的剑术是无剑，这部电影便能看到无剑的剑气。&lt;/p&gt;
&lt;p&gt;如果要推荐一本书的话，我选择 《枪炮、病菌与钢铁》，只狠怎么这么晚才看这本书，以前在书店很多次看到过，看标题没想到这么这么精彩。然后陆续看了雷蒙德的其他作品，深深被他的思想折服，看他的书，仿佛面对着一个地球仪，转来转去，了解文明在各地萌芽生根发展，真的很迷人。&lt;/p&gt;
&lt;p&gt;2024 又慢慢学会爱了。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to fix cors issue in clerk nextjs project</title>
    <link href="https://stonegate.me/posts/how-to-fix-cors-issue-in-clerk-nextjs-project/" />
    <updated>2023-10-06T00:00:00Z</updated>
    <id>https://stonegate.me/posts/how-to-fix-cors-issue-in-clerk-nextjs-project/</id>
    <content type="html">&lt;p&gt;If you&#39;re building a web application with Next.js and using the Clerk authentication service, you may encounter a CORS (Cross-Origin Resource Sharing) issue when making API requests outside the app. This issue occurs when the browser blocks requests to a different domain than the one the app is hosted on.&lt;/p&gt;
&lt;p&gt;With the follow steps, we&#39;ll walk through how to fix the CORS issue in a Clerk Next.js project.&lt;/p&gt;
&lt;h2 id=&quot;step-1-add-cors-headers-to-the-api-endpoint&quot;&gt;Step 1. Add CORS Headers to the API Endpoint&lt;/h2&gt;
&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, Next.js!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Origin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Methods&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GET, POST, PUT, DELETE, OPTIONS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Headers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type, Authorization&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-2-update-middleware&quot;&gt;Step 2. Update middleware&lt;/h2&gt;
&lt;p&gt;In this middleware, we first checks if the incoming request is an OPTIONS request, which is a preflight request that is sent by the browser to check if a cross-origin request is allowed. If it is an OPTIONS request, the middleware returns a response with headers that allow cross-origin requests. If it&#39;s not an OPTIONS request, the middleware calls the authMiddleware function from the Clerk Next.js library.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; authMiddleware &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@clerk/nextjs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; NextFetchEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NextRequest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;next/server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;middleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NextRequest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; NextFetchEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;method &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; origin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;origin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Origin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; origin &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Methods&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;GET, POST, PUT, DELETE, OPTIONS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Allow-Headers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type, Authorization,  Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Access-Control-Max-Age&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;86400&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; auth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;authMiddleware&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we walked through how to fix the CORS issue in a Clerk Next.js project. We modified the API endpoint to allow cross-origin requests, and added some headers to the response to allow the browser to access the resource.&lt;/p&gt;
&lt;p&gt;With these changes, you can now make API requests from a different domain in your Clerk Next.js project without encountering a CORS issue.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to set up a Prisma Client That Uses MongoDB as a Second Database</title>
    <link href="https://stonegate.me/posts/how-to-set-up-a-prisma-client-that-uses-mongodb-as-a-second-database/" />
    <updated>2023-08-27T00:00:00Z</updated>
    <id>https://stonegate.me/posts/how-to-set-up-a-prisma-client-that-uses-mongodb-as-a-second-database/</id>
    <content type="html">&lt;p&gt;最近在 Recos 项目中将字幕文件的存储转移到了 Mongo 数据库，前端项目采用的是 Nextjs + Prisma 的框架，于是需要 Prisma 添加 Mongo 的支持，其中还是遇到了一些小坑，在此记录下。&lt;/p&gt;
&lt;p&gt;Prisma 本身是不支持连接到多个数据库的，实现方法是在 &lt;code&gt;prisma&lt;/code&gt; 目录中新建一个文件名为 &lt;code&gt;mongo_schema.prisma&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-prisma&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-prisma&quot;&gt;generator client {
  provider = &quot;prisma-client-js&quot;
  output   = &quot;./generated/mongo_client&quot;
}

datasource db {
  provider = &quot;mongodb&quot;
  url      = env(&quot;MONGO_URL&quot;)
}

model subtitle {
  id_            String @id @default(auto()) @map(&quot;_id&quot;) @db.ObjectId
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主要是在 client 里面添加 output 字段，首先在项目 .&lt;code&gt;env&lt;/code&gt; 文件中添加 &lt;code&gt;MONGO_URL&lt;/code&gt;,然后执行 &lt;code&gt;prisma generate --schema=prisma/mongo_schema.prisma&lt;/code&gt; ，就会在 &lt;code&gt;prisma&lt;/code&gt; 目录下生成 prisma client 的代码。&lt;/p&gt;
&lt;p&gt;通过以下方法引入后就可以使用了。&lt;/p&gt;
&lt;pre class=&quot;language-prisma&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-prisma&quot;&gt;import { PrismaClient as PrismaMongoClient } from &quot;../prisma/generated/mongo_client&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;值得注意的是，如果你连接到 Mongo 数据库报以下错误时&lt;/p&gt;
&lt;pre class=&quot;language-prisma&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-prisma&quot;&gt;import { PrismaClient as PrismaMongoClient } from &quot;../prisma/generated/mongo_client&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以尝试在环境变量文件 &lt;code&gt;MONGO_URL&lt;/code&gt; 后添加 &lt;code&gt;?authSource=admin&lt;/code&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My 2022 Review</title>
    <link href="https://stonegate.me/posts/my-2022-review/" />
    <updated>2023-03-04T00:00:00Z</updated>
    <id>https://stonegate.me/posts/my-2022-review/</id>
    <content type="html">&lt;h1 id=&quot;2022&quot;&gt;2022 年度回顾&lt;/h1&gt;
&lt;p&gt;今天已经是 3 月 4 日了，2023 年的 3 月 4 日，这个春天特别的冷，在这个寒冷的夜里，终于想起来要补上去年的总结了。最近渐渐开始使用 Notion 来记录每天完成了哪些工作，每天到了晚上下班的时候已经不太起来白天工作的细节，每天太多细碎的工作导致很难记得太多细节，这让我有点担心。既然记不起来，那就把 GitHub Profile 的 2022 记录翻出来看，从 12 月到 1 月，也大概知道 2022 都忙了什么。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;个人项目&lt;/h2&gt;
&lt;p&gt;2022 年慢慢在尝试自己做一些用 NextJs 开发的项目，使用 Figma 进行设计，虽然都没有推广成功，但是对于产品经理的角色有了更多的认识，也积累了不少的经验。产品功能的初始设计是非常重要，不然很容易完成一个先天不足的产品。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lens.ink&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lens.ink&quot;&gt;lens.ink&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lens.ink 是一个基于 Lens Protocol 的 web 应用，目标是想做一个 lens 用户的应用聚合页，在这里可以快速访问 lens 生态内的应用。最后的结果并不如人意，首先是一开始的需求设定就不太正确，这并不是一个很好的需求，最终完成的项目质量也不够高。&lt;/p&gt;
&lt;p&gt;这个项目是我最开始使用 NextJs 开发的项目，后来新项目都在用 NextJs 了，工作依旧在用 NuxtJs。另外就是第一次用 GraphQL 的 API。Tailwinds 也用的越来越熟练了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Web3Helpers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web3helpers.xyz&quot;&gt;Web3Helpers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/my-2022-review/gi-6EovuRy-1995.avif 1995w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/my-2022-review/gi-6EovuRy-1995.webp 1995w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/my-2022-review/gi-6EovuRy-1995.png&quot; alt=&quot;&quot; width=&quot;1995&quot; height=&quot;764&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Web3Helpers 是一个 web3 工具集合应用，目标是想把 web3 开发中的一些小任务 UI 化，比如快速创建一个 ERC20 的代币，解析 ETH 的 &lt;code&gt;rawTransaction&lt;/code&gt;, 或者使用 JSONRPC 的请求。在开发过程中接触了 Solana Aptos Sui 等其他工链，对于这些链有了基本的认识，基于需求也开发了 &lt;a href=&quot;https://github.com/web3helpers/wallets-hooks&quot;&gt;Wallet Hooks&lt;/a&gt;, 开发过程中对于 react hooks 也有了更多的认识。对于每一个小的工具来说都是一个相对独立的应用，所以开发了对应的方便复用的 UI 组件库以及 cli 工具。&lt;/p&gt;
&lt;p&gt;现在来看，web3helpers 还是一个不错的项目，2023 年还是值得继续开发的，可能需要开发更复杂的工具，真是添加一个简单的 swap 工具也是个不错的主意。&lt;/p&gt;
&lt;h2 id=&quot;-2&quot;&gt;工作&lt;/h2&gt;
&lt;p&gt;2022 年最重要的工作是在项目中全面使用 typescript。从一开始的各种不顺手到后来变成了不可缺少。typescript 确实极大的提升了 js 的开发体验，也减少了 bug 的发生。一个例子是我写了一个 cli 工具，用于将后端项目的 api 接口文件 自动生成对应的 aixos 请求库，默认支持 typescript，这样在使用这些 api 时就不用再输入返回数据的字段名了，因为 ide 会自动给出提示，在此之前是需要从浏览器中获取到接口返回的数据，再复制对应的字段到代码，这样很容易造成后端修改了字段，前端却没有及时更新的问题，又或者字段名 typo 却没有及时发现。&lt;/p&gt;
&lt;p&gt;另外一个工作是建立了 &lt;code&gt;website-template&lt;/code&gt; 以及 &lt;code&gt;dapp-template&lt;/code&gt; 项目。前者用于快速创建官网项目，这一年可是写了不少官网啊，后者用于快速创建 dapp。Template 主要是统一了团队内部的插件的使用，并包含了常用的组件。&lt;/p&gt;
&lt;p&gt;我利用十一的假期时间搭建了 &lt;code&gt;abmatrix-ui&lt;/code&gt; 项目，目标是想把工作中常用的一些组件聚合起来，方便以后用的时候快速复用。但是并没有得到很好的维护和利用。&lt;/p&gt;
&lt;p&gt;年底几个月都在忙 SBTAuth SDK 的开发，这对于我来说是一个蛮大的挑战，过程中学习到了很多新的知识，尤其是浏览器内消息相关的接口，也一直在不断思考项目的架构以及实现。&lt;/p&gt;
&lt;p&gt;2023 年有一个很重要的任务是要升级到 &lt;code&gt;NuxtJs3.0 &lt;/code&gt;以及对应的&lt;code&gt; Vue3.0&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&quot;-3&quot;&gt;生活&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/my-2022-review/9gd3kQfgte-2992.avif 2992w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/my-2022-review/9gd3kQfgte-2992.webp 2992w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/my-2022-review/9gd3kQfgte-2992.jpeg&quot; alt=&quot;&quot; width=&quot;2992&quot; height=&quot;1681&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;2022 年疫情终于在 n 多次的核酸后结束了，健康码终于不用再打开了，感恩家人朋友都顺利度过了。&lt;/p&gt;
&lt;p&gt;生活上似乎没有什么大的改变，我开始在咖啡店学习做拉花了，每天进步一点点，越来越爱咖啡了。
今年没有出去玩，后半年读了一些很多魏晋南北朝的书，之前火起来的魏晋热现在终于补上了，果然是个荒谬又迷人的时代。最推荐的书当属罗新老师的 《&lt;a href=&quot;https://book.douban.com/subject/35909188/&quot;&gt;漫长的余生&lt;/a&gt;》。
最幸运的在 2022 的最后一天，认识了一个很喜欢的女生，希望 2023 年一切顺利吧。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>NestedScrollView 使用指南</title>
    <link href="https://stonegate.me/posts/nestedscrollview/" />
    <updated>2023-01-30T00:00:00Z</updated>
    <id>https://stonegate.me/posts/nestedscrollview/</id>
    <content type="html">&lt;h2 id=&quot;nestedscrollview&quot;&gt;NestedScrollView 是什么&lt;/h2&gt;
&lt;p&gt;通常当 App 页面内使用滚动组件时，为了优化用户体验，我们需要将列表的滚动区域最大化，这时候就需要 NestedScrollView 组件了，NestedScrollView 用于管理多个滚动组件，它可以让多个滚动组件嵌套滚动，这样就可以让滚动组件的滚动区域最大化。NesetedScrollView 组件最常用的场景是 SliverAppBar + TabView。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;基本用法&lt;/h2&gt;
&lt;p&gt;使用 NestedScrollView 组件，我们需要使用 SliverOverlapAbsorber 和 SliverOverlapInjector 两个组件配合使用，SliverOverlapAbsorber 用于监听滚动事件，SliverOverlapInjector 用于将 SliverOverlapAbsorber 的滚动事件注入到子组件中。&lt;/p&gt;
&lt;pre class=&quot;language-dart&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-dart&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    headerSliverBuilder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BuildContext&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool innerBoxIsScrolled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;SliverOverlapAbsorber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          handle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sliverOverlapAbsorberHandleFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          sliver&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SliverAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Snapping Nested SliverAppBar&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            floating&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            snap&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            expandedHeight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            forceElevated&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; innerBoxIsScrolled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    body&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BuildContext&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        slivers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token class-name&quot;&gt;SliverOverlapInjector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              handle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sliverOverlapAbsorberHandleFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;tabview&quot;&gt;使用 TabView&lt;/h2&gt;
&lt;pre class=&quot;language-dart&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-dart&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    headerSliverBuilder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BuildContext&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool innerBoxIsScrolled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;SliverOverlapAbsorber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          handle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sliverOverlapAbsorberHandleFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          sliver&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SliverAppBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-literal&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Snapping Nested SliverAppBar&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            floating&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            snap&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            expandedHeight&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            forceElevated&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; innerBoxIsScrolled&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            bottom&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TabBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                tabs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    body&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TabBarView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;BuildContext&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CustomScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        slivers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;token class-name&quot;&gt;SliverOverlapInjector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              handle&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NestedScrollView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sliverOverlapAbsorberHandleFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;refrfeshindicator&quot;&gt;使用 RefrfeshIndicator&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;NestedScrollView&lt;/code&gt; 中使用 &lt;code&gt;RefreshIndicator&lt;/code&gt; 时，需要设置 &lt;code&gt;notificationPredicate&lt;/code&gt; 属性，否则会出现刷新指示器无法显示的问题。&lt;/p&gt;
&lt;pre class=&quot;language-dart&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-dart&quot;&gt; &lt;span class=&quot;token class-name&quot;&gt;RefreshIndicator&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        onRefresh&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        notificationPredicate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;-2&quot;&gt;自定义顶部样式&lt;/h2&gt;
&lt;p&gt;您可以修改 &lt;code&gt;FlexiableSpaceBar&lt;/code&gt; 组件修改滚动时的头部效果。&lt;/p&gt;
&lt;pre class=&quot;language-dart&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-dart&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stretchModes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;StretchMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fadeTitle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxHeight &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxExtent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; double stretchOpacity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;clampDouble&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxHeight &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxExtent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    opacity&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; stretchOpacity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    child&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>My 2021 Review</title>
    <link href="https://stonegate.me/posts/my-2021-review/" />
    <updated>2022-01-28T00:00:00Z</updated>
    <id>https://stonegate.me/posts/my-2021-review/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;2021 年度回顾&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;&quot;&gt;新工作&lt;/h2&gt;
&lt;p&gt;2021 年开始了新工作，做起来以前一直想做的事。从慢慢熟悉到常常加班，走过了整整一年。2021 年对我来说是一个新的开始，总体走得还是挺顺利的。&lt;/p&gt;
&lt;p&gt;技术上来说从零开始学习 web 开发，现在 Js Ts Vue 都有很好的掌握，对于状态管理也有了更深刻的认识。欠缺的部分在于 React 以及 Html Dom Css 基础还不够深厚。这也是新的一年需要提高的地方。&lt;/p&gt;
&lt;p&gt;Flutter 用起来越来越顺手了，各个状态管理插件都有接触，项目整体的组织也驾轻就熟了， FFI 经过几个项目使用也很熟练了。需要提高的地方在于提升 App 的性能，目前这块没有做的很好。&lt;/p&gt;
&lt;p&gt;其他熟悉的语言包括 Ruby(快忘记了) Php Golang Rust Swift Kotlin,这些都有锁学习，但是都不够深入，新的一年应把重点放在 Swift &amp;amp; Kotlin，这两种语言是开发原生应用的基础，新的一年希望能完成自己的原生应用作品。&lt;/p&gt;
&lt;p&gt;此外，还学习了很多区块链的知识。Solana 看起来还不错，希望我的钱包应用能尽快完成。&lt;/p&gt;
&lt;p&gt;有两点需要反思：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;学习的内容可能需要更集中一些，目前还是太分散了，需要确定自己真正需要的，然后花更多的时间。&lt;/li&gt;
&lt;li&gt;下半年加班时间太多了，还是应该给生活多留一些时间。&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Thinking in React</title>
    <link href="https://stonegate.me/posts/thinking-in-react/" />
    <updated>2021-10-22T00:00:00Z</updated>
    <id>https://stonegate.me/posts/thinking-in-react/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;本文翻译自 https://beta.reactjs.org/learn/thinking-in-react&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;React 可以改变你看待设计以及开发应用的想法。在使用 React 之前，你看到的可能是茫茫一片树林，之后你会看清楚树林中的每一棵树。React 让设计系统和 UI 状态管理变得简单。在这个教程中，我们将帮助你使用 React 完成一个支持搜索的产品表格的应用。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;从设计图纸开始&lt;/h2&gt;
&lt;p&gt;假设你拥有一个 JSON API 接口，以及设计师的设计图。&lt;/p&gt;
&lt;p&gt;JSON API 返回的数据如下：&lt;/p&gt;
&lt;pre&gt;[
  { category: &quot;Fruits&quot;, price: &quot;$1&quot;, stocked: true, name: &quot;Apple&quot; },
  { category: &quot;Fruits&quot;, price: &quot;$1&quot;, stocked: true, name: &quot;Dragonfruit&quot; },
  { category: &quot;Fruits&quot;, price: &quot;$2&quot;, stocked: false, name: &quot;Passionfruit&quot; },
  { category: &quot;Vegetables&quot;, price: &quot;$2&quot;, stocked: true, name: &quot;Spinach&quot; },
  { category: &quot;Vegetables&quot;, price: &quot;$4&quot;, stocked: false, name: &quot;Pumpkin&quot; },
  { category: &quot;Vegetables&quot;, price: &quot;$1&quot;, stocked: true, name: &quot;Peas&quot; }
]&lt;/pre&gt;
&lt;p&gt;设计图如下：
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/thinking-in-react/QTuZ9F0xVj-572.avif 572w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/thinking-in-react/QTuZ9F0xVj-572.webp 572w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/thinking-in-react/QTuZ9F0xVj-572.png&quot; alt=&quot;Design Image&quot; width=&quot;572&quot; height=&quot;646&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;你将通过以下五个步骤来完成这个 UI 设计。&lt;/p&gt;
&lt;h3 id=&quot;ui&quot;&gt;步骤一 将 UI 划分成组件&lt;/h3&gt;
&lt;p&gt;首先你需要在设计图中划出组件及子组件并命名。如果你和设计师一起工作，可能设计师已经在设计工具里对这些组件进行了命名，你可以查看。&lt;/p&gt;
&lt;p&gt;根据你的背景不同，将设计图纸划分为组件一般有以下几种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编程&lt;/strong&gt; 使用你创建函数或这对象的思路，其中一种思路是 &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;单一任务原则&lt;/a&gt;, 是指一个组件应该只完成一项任务。如果它一直变大，那就应该分成更小的子组件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt; 根据你创建 CSS 选择器的思路（但是组件没有这么颗粒化）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;设计&lt;/strong&gt; 根据你设计图层的思路。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你的 JSON 结构好的话，你会发现它可以对应到 UI 结构的组件。这是因为 UI 和数据结构通常有相同的信息结构，也就是形状。将 UI 划分成每一个组件，每一个组件关联一个数据结构。&lt;/p&gt;
&lt;p&gt;在这个屏幕上有五个组件。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://stonegate.me/posts/thinking-in-react/LINQwRlxa--1200.avif 1200w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://stonegate.me/posts/thinking-in-react/LINQwRlxa--1200.webp 1200w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://stonegate.me/posts/thinking-in-react/LINQwRlxa--1200.png&quot; alt=&quot;Components&quot; width=&quot;1200&quot; height=&quot;744&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;FilterableProductTable (灰色) 表示整个 APP&lt;/li&gt;
&lt;li&gt;Searchbar (蓝色) 接受用户输入&lt;/li&gt;
&lt;li&gt;ProductTable(紫色) 展示和过滤根据用户输入获取的列表&lt;/li&gt;
&lt;li&gt;ProductCategoryRow (绿色) 每一个分类头部&lt;/li&gt;
&lt;li&gt;ProductRow （黄色） 展示产品列&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你观察 ProductionTable(紫色), 你会发现表格头部(包括名字和价格标签) 并不是它自己的组件. 这是一种偏好，你可以选择任何一种方式。对于这个例子，它作为 ProductTable 一部分是因为它属于 ProductTable 的列表。然而，如果表格头部变得很复杂的话（比如新增排序）, 使用单独的 ProducTableHeader 组件就很有必要了。&lt;/p&gt;
&lt;p&gt;Now that you’ve identified the components in the mockup, arrange them into a hierarchy. Components that appear within another component in the mockup should appear as a child in the hierarchy:
现在你已经在设计图中分出了组件，并进行了分组。设计图中组件里的组件对应为架构里的子组件。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FilterableProductTable
&lt;ul&gt;
&lt;li&gt;SearchBar&lt;/li&gt;
&lt;li&gt;ProductTable
&lt;ul&gt;
&lt;li&gt;ProductCategoryRow&lt;/li&gt;
&lt;li&gt;ProductRow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;react&quot;&gt;步骤二 用 React 构建静态页面&lt;/h3&gt;
&lt;p&gt;现在你已经有了组件树，是时候构建应用了。最直接的做法就是构建一个版本，仅使用数据模型渲染 UI，不添加任何互动。往往构建静态页面是较为容易的，之后再增加互动。构建静态页面需要大量的敲键盘且不需要太多思考，但是增加互动需要大量的思考，已经不那那么多代码。&lt;/p&gt;
&lt;p&gt;要构建一个应用渲染你的数据模型，你需要先实现复用组件的组件并且通过 Props 传值。Props 是一种将数据从父组件传递到子组件的方法。如果你对状态管理很熟悉，请不要在构建静态版本时使用状态管理，状态管理通常用于互动，也就是数据会随着时间改变。对于静态页面并不需要。&lt;/p&gt;
&lt;p&gt;你可以自上而下构建组件，从组件架构里较高层级的组件（比如 FilterableProductTable ）开始，也可以自下而上构建组件，从组件架构里较底层的组件（比如 ProductionRow ）开始。对于简单的应用，一般采用自上而下的方式，对于大型的项目，采用自下而上的方式更为容易。&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProductCategoryRow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; category &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;th colSpan&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;th&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProductRow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; product &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stocked &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;td&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;td&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;td&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;price&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;td&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ProductTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; products &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastCategory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  products&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;category &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; lastCategory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ProductCategoryRow category&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ProductRow product&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    lastCategory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; product&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;category&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;table&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;thead&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;th&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Name&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;th&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;th&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Price&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;th&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;tr&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;thead&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;tbody&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;tbody&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;table&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt; placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Search...&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;label&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;checkbox&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Only show products &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; stock
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;label&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;form&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FilterableProductTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; products &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SearchBar &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ProductTable products&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;products&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PRODUCTS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fruits&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Apple&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fruits&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Dragonfruit&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fruits&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Passionfruit&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vegetables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Spinach&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vegetables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pumpkin&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vegetables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;price&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;$1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;stocked&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Peas&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FilterableProductTable products&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PRODUCTS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不要对这段代码感到担心，在这个教程，我们更注重概念而不是代码。你可以通过&lt;a href=&quot;https://beta.reactjs.org/learn/describing-the-ui&quot;&gt;Describing the UI&lt;/a&gt; 更多了解这段代码。&lt;/p&gt;
&lt;p&gt;构建组件完成后，你将拥有一个组件库来渲染你的数据。因为这是一个静态数据，组件将只返回 JSX 。顶层的组件 (FilterableProductTable) 将会接受数据模型作为 Prop 。这就是所谓的单向数据流，因为数据从顶层组件流向底层的组件。&lt;/p&gt;
&lt;h3 id=&quot;-2&quot;&gt;步骤三 找到最小化但完整的应用状态&lt;/h3&gt;
&lt;p&gt;想要 UI 用互动性，你需要运行用户改变数据模型。你需要通过状态管理来实现。&lt;/p&gt;
&lt;p&gt;状态其实是你的应用需要记住的实时变化的数据的最小集合。构建状态最重要的原则就是不要重复 &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt;。找出你的应用所需要状态的最小代表，剩余的则通过计算实现。例如，如果你在构建一个购物清单，你可以将商品存储在一个数组里。如果你想展示商品的数量，不要存储数据在另一个状态值里，而是使用数组的长度。&lt;/p&gt;
&lt;p&gt;以下是应用里的所有数据：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原始产品列表&lt;/li&gt;
&lt;li&gt;用户输入内容&lt;/li&gt;
&lt;li&gt;选择框数据&lt;/li&gt;
&lt;li&gt;过滤后的产品列表&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这其中那些是状态值？那些不是呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据不会改变，那一定不属于状态&lt;/li&gt;
&lt;li&gt;数据来自于父组件，一定不属于状态&lt;/li&gt;
&lt;li&gt;可以通过已有的状态值和数据值计算，那一定不属于状态值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;剩余的基本都是状态值。&lt;/p&gt;
&lt;p&gt;让我们一个一个来分析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原始产品数据通过 Props 传值，不属于状态值。&lt;/li&gt;
&lt;li&gt;搜索值是状态值因为它会随着时间改变并且不能计算而来。&lt;/li&gt;
&lt;li&gt;选择框的值是状态值因为会随着时间改变并且不能计算而来。&lt;/li&gt;
&lt;li&gt;过滤后的产品不属于状态值，因为它可以通过原始产品列表和搜索值以及选择框数据计算而来。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可见，只有搜索值和选择框的值属于状态值。&lt;/p&gt;
&lt;pre&gt;
#### 深入
在 React 中有两种数据 Props 和 State,这两者有很大不同。
* Props 像你在函数中的传入变量。它帮助父组件将数据传值给子组件，修改子组件的样式。比如， Form 可以传递颜色值给 Button 。
* State 像组件的记忆。它帮助组件追踪一些信息并根据信息改变自己的状态。比如，Button 需要追踪 isHovered 状态值。

Props 和 State 是不同的，但是它们一起工作，父组件经常保持一些信息在状态值里，通过 Prop 将数据传递给子组件。第一次阅读时感到疑惑是正常的，这需要通过联系慢慢熟悉。
&lt;/pre&gt;
&lt;h3 id=&quot;-3&quot;&gt;步骤四 判断状态所处位置&lt;/h3&gt;
&lt;p&gt;在确定应用的状态值后，你需要判断哪一个组件用来负责状态修改，或者拥有状态值。记住： React 使用单向数据流，从父级组件传递数据到字组件。哪个组件应该拥有状态值可能不是立刻清晰。当你的第一次接触时会很有挑战，你可以通过以下步骤来完成。&lt;/p&gt;
&lt;p&gt;对于你应用里的每一个状态值：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;找出根据状态值渲染数据的组件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;找出它们最接近的共同父级组件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确定状态值的位置：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通常，你可以将状态值放在共同父组件里。&lt;/li&gt;
&lt;li&gt;你可以将状态值放在共同父组件更上层的组件中。&lt;/li&gt;
&lt;li&gt;如果你找不到一个组件可以放置状态，你可以单独创建一个新的组件，并把他添加为共同父组件的上层组件。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在前面的步骤中，你发现了应用中需要两个状态值：搜索框输入值和选择框输入值。在这个例子中，它们总是共同出现，因此可以认为它们是同一个状态。&lt;/p&gt;
&lt;p&gt;现在我们来整理这些状态值：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;找到使用状态值的组件
&lt;ul&gt;
&lt;li&gt;ProructTable 需要更具状态过滤产品列表。&lt;/li&gt;
&lt;li&gt;SearchBar 需要展示状态值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;找到共同的父组件。最先的共同父组件是 FilterableProductTable 。&lt;/li&gt;
&lt;li&gt;决定状态值位置。状态将位于 FilterableProductTable 。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此状态值将位于 FilterableProductTable 。&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://beta.reactjs.org/reference/usestate&quot;&gt;useState(hook)&lt;/a&gt; 来管理组件状态。钩子可以帮助你在组件的渲染过程中。在 FilterableProductTable 最上层添加两个状态变量并赋予初始值。&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FilterableProductTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; products &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setFilterText&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inStockOnly&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setInStockOnly&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后， 将 filterText 和 isStockOnly 传递到 ProductTable 和 SearchBar 。&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SearchBar filterText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; inStockOnly&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;inStockOnly&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ProductTable products&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;products&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; filterText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; inStockOnly&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;inStockOnly&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可以看到应用如何执行。通过修改 useState(&#39;&#39;) 为 useState(&#39;fruit&#39;) 修改 filerText 初始值。你可以看到搜索值和表格更新。&lt;/p&gt;
&lt;p&gt;在上面的 sandbox 里， ProductTable 和 SearchBar 读取 filerText 和 inStockOnly props 来渲染表格，输入框和选择框。例如，这里是 SearchBar 设置初始值。&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SearchBar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; filterText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; inStockOnly &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;form&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input
        type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;
        value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Search...&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Refer to the Managing State to dive deeper into how React uses state and how you can organize your app with it.&lt;/p&gt;
&lt;p&gt;你可以通过 &lt;a href=&quot;https://beta.reactjs.org/learn/managing-state&quot;&gt;管理状态&lt;/a&gt; 来了解更多关于 React 使用状态以及你如何在应用里管理状态。&lt;/p&gt;
&lt;h3 id=&quot;-4&quot;&gt;步骤五 添加逆向数据流&lt;/h3&gt;
&lt;p&gt;现在你的应用可以正确渲染 props 和 states 流向。但是要支持根据用户输入修改状态，你需要支持数据从另一个方向流动: 下层的表单组件需要更新 FilterableProductTable 状态。&lt;/p&gt;
&lt;p&gt;React 保证数据流动是精确的，但是它需要更多的代码来实现双向绑定。如果你试着在输入框输入数据或者选择选择框，你会发现 React 忽略你的输入。这是有意为之的。通过 &lt;code&gt;&amp;lt;input value={filterText}&amp;gt;&amp;lt;/input&amp;gt;&lt;/code&gt;,你已经设置输入的值永远等于 filterText 状态值，因为 filterText 的状态值从来没有被设置，输入值就不会变。&lt;/p&gt;
&lt;p&gt;你想要根据用户修改输入值更新状态。状态值属于 FilterableProductTable ,因此只有它可以使用 setFilterText 和 setInStockOnly 。为了让 SearchBar 更新 FilterableProductTable 的状态值，你需要传递这些函数到 SearchBar 。&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FilterableProductTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; products &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setFilterText&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;inStockOnly&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setInStockOnly&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;SearchBar
        filterText&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        inStockOnly&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;inStockOnly&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        onFilterTextChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;setFilterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        onInStockOnlyChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;setInStockOnly&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Inside the SearchBar, you will add the onChange event handlers and set the parent state from them:&lt;/p&gt;
&lt;p&gt;在 SearchBar 中，你可以添加 onChange 事件处理和设置父级组件。&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input
  type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;
  value&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filterText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  placeholder&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Search...&quot;&lt;/span&gt;
  onChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onFilterTextChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在应用正常工作了。&lt;/p&gt;
&lt;p&gt;你可以在 &lt;a href=&quot;https://beta.reactjs.org/learn/adding-interactivity&quot;&gt;添加互动&lt;/a&gt; 学习所以关于处理事件更新状态。&lt;/p&gt;
</content>
  </entry>
</feed>