<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>w2solo - 独立开发者社区</title>
    <link>https://beta.w2solo.com/</link>
    <description>w2solo - 独立开发者社区社区最新发帖.</description>
    <language>en-us</language>
    <item>
      <title>布尔目标 app 诞生记</title>
      <description>&lt;p&gt;“人生如旷野，我亦是行人”。&lt;/p&gt;

&lt;p&gt;布尔目标产品的初衷是希望能够将我们短短的一生中的计划列举出来，然后逐一实现。人生若白驹过隙，总是会过的很快，如何在有限的人生中，活的精彩，活出自己想要的样子，所以需要目标驱动。传统的清单应用只是专注于近期的事件，但是对于长期的目标，缺乏追踪，而 “布尔目标” 正应运而生。&lt;/p&gt;

&lt;p&gt;之前在 “布尔智汇” 客户端里面 “人生计划” 里面已实现该功能，但是考虑到移动端更加方便，因此，重新开发了 “布尔目标” app，账户、数据与布尔智汇通用，移动端用布尔目标，桌面端用布尔智汇，方便用户使用。&lt;/p&gt;

&lt;p&gt;在这里，您可以分类设定人生的各个目标，完成该目标后，后面勾选完成即可。目标和进度统统会显示出来，让您知道计划的完成情况。&lt;/p&gt;

&lt;p&gt;不同的人生阶段有不同的目标，但是我只是希望我们不要陷入盲目的忙碌当中，让人生过的充实且有意义。&lt;/p&gt;

&lt;p&gt;App 代码已开源，欢迎大家访问并下载：&lt;/p&gt;

&lt;p&gt;源码地址：&lt;a href="https://gitee.com/riverbird/bool-target" rel="nofollow" target="_blank"&gt;https://gitee.com/riverbird/bool-target&lt;/a&gt;
&lt;img src="https://img.way2solo.com/photo/riverbird/cadb9bfc-fd42-4de1-b2e6-a7889924df1c.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/riverbird/d56d152b-3044-44f9-8b5b-f3d9ad4e4843.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/riverbird/c8a45efe-7e52-4bd8-b295-d1918a71e455.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/riverbird/5f3a0aca-4d04-44db-855d-fd32f2ba0ca0.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>riverbird</author>
      <pubDate>Fri, 17 Jul 2026 10:06:28 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7781</link>
      <guid>https://beta.w2solo.com/topics/7781</guid>
    </item>
    <item>
      <title>意图共鸣科技《智能体三角模型白皮书》：人文交互内核——给 AI 做 “岗前培训”</title>
      <description>&lt;p&gt;你招了一个新员工，脑子很聪明，学东西快，但没上过班。&lt;/p&gt;

&lt;p&gt;你让他接客户电话，他说话冷冰冰的，客户挂了电话就投诉。你让他处理客诉，他直接说 “按公司规定，这事没法办”，客户更生气了。你让他给客户发消息，他发的每条都像机器人写的。&lt;/p&gt;

&lt;p&gt;你发现，他不是不努力，是根本不知道 “在公司里该怎么说话、怎么做人”。&lt;/p&gt;

&lt;p&gt;于是你开始给他做培训。&lt;/p&gt;

&lt;p&gt;你告诉他，接待客户要先听他说完，别急着打断。客户有情绪要先安抚，别上来就讲道理。不能说 “这是规定”，要说 “我帮您看看有没有别的办法”。涉及到钱的事不能自己做决定，要先请示。客户问敏感信息不能随便给。出了事要有记录，不能说不清楚。&lt;/p&gt;

&lt;p&gt;你把这些规则一条一条列出来，教给他。&lt;/p&gt;

&lt;p&gt;慢慢地，他变了。接电话时客户能感受到他的耐心，处理投诉时客户觉得他在真心帮忙，发消息时语气对了分寸也对了。他不是更聪明了，是知道规矩了。&lt;/p&gt;

&lt;p&gt;这就是 “人文交互内核”。&lt;/p&gt;

&lt;p&gt;它不是让 AI 变聪明，而是给 AI 装一套行为准则——教它怎么说话、怎么做人、怎么守住底线。&lt;/p&gt;

&lt;p&gt;在三角模型中，人文交互内核是与通用认知基座、私有知识域平齐的 “一等架构层”。它不是大模型的附属品，不是调调提示词就能解决的事，而是一套独立的、完整的交互规则体系。&lt;/p&gt;

&lt;p&gt;具体来说，AI 需要被教会很多事情。&lt;/p&gt;

&lt;p&gt;它得知道自己是谁。是客服还是顾问？说话是亲切还是专业？角色定好了，语气才不会乱，今天像同事明天像老板这种事情不能发生。&lt;/p&gt;

&lt;p&gt;它还得学会看人脸色。客户生气了，先安抚情绪，别急着讲道理。客户焦虑了，先给个共情的回应，再说方案。先处理心情再处理事情，这条规则很简单，但做到了，AI 就从一个冷冰冰的机器变成了一个有温度的服务者。&lt;/p&gt;

&lt;p&gt;有些事它绝对不能做。不能承诺 “百分百解决”，不能代替人做高风险决策，比如退款、签约、自主变更供应商，不能贬低同行。一旦遇到边界外的事，主动说 “我帮您转人工”。这是防止 AI 闯祸的防火墙。&lt;/p&gt;

&lt;p&gt;它的设计原则是辅助人工，而不是替代人工。遇到高客单价决策、客户情绪波动、复杂投诉，AI 会自动判断需要人工介入，但它不中断对话，而是继续陪着客户，同时把完整对话摘要、用户意图、情绪状态悄悄同步给人工。人工接管的时候，客户感觉不到 “转接”，体验是连续的。&lt;/p&gt;

&lt;p&gt;它还得学会 “记性不好”。聊的过程中可以临时记住你的偏好，比如你喜欢简洁的回答，但聊完了就得忘掉，不能把你说的隐私存在它那里。身份证、银行卡、健康信息，一律不问不存。&lt;/p&gt;

&lt;p&gt;遇到听不懂的话，它会说 “不好意思，我没太明白，要不您说说具体想了解什么？” 问题太模糊，它会主动给你几个选项帮你把问题说清楚。管不了的事，它会告诉你找谁。&lt;/p&gt;

&lt;p&gt;每次关键对话，它还会记录——你问了什么、它怎么理解的、它怎么决策的、最后回了什么。这不是为了监控，是为了出了纠纷的时候能还原事实，不扯皮。金融、医疗、法律这些强监管行业，这条是硬要求。&lt;/p&gt;

&lt;p&gt;这七大模块合在一起，就是人文交互内核。&lt;/p&gt;

&lt;p&gt;它不是大模型本来就有的。大模型很聪明，但没人教过它 “在公司里该怎么做人”。人文交互内核，就是专门给 AI 做的岗前培训。&lt;/p&gt;

&lt;p&gt;一个经过培训和没经过培训的 AI，差别有多大？你可以试试，找个 AI 工具，问它同一个问题：“你们有什么优惠吗？”&lt;/p&gt;

&lt;p&gt;没培训的，可能直接说 “没有”。有培训的，会说：“目前没有直接优惠，但您如果是老客户，我可以帮您问问有没有专属折扣。方便告诉我您之前用过我们的服务吗？”&lt;/p&gt;

&lt;p&gt;同样的问题，不一样的回答。第一个冷冰冰，第二个有温度、有分寸、知道边界。这就是人文交互内核的价值——让 AI 不仅聪明，而且得体。&lt;/p&gt;</description>
      <author>XinIRP</author>
      <pubDate>Thu, 16 Jul 2026 22:05:50 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7780</link>
      <guid>https://beta.w2solo.com/topics/7780</guid>
    </item>
    <item>
      <title>AI 写的 React 组件,合并前必查的 6 个坏味道——每个都有代码对比</title>
      <description>&lt;p&gt;先说一句：这篇不是让你别用 AI 写 React。&lt;/p&gt;

&lt;p&gt;我自己每天用 Claude Code + Cursor,产出效率至少翻倍。但要说得罪的话——&lt;strong&gt;AI 生成的 React 代码,直接合并的风险,比你想象的高&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;不是因为 AI 语法错。语法它比你还熟。&lt;/p&gt;

&lt;p&gt;是因为 React 的"最佳实践"是一堆&lt;strong&gt;上下文相关&lt;/strong&gt;的判断:什么时候用 useEffect、什么时候不用;state 该放哪一层;key 用什么;要不要 memo。这些判断需要看&lt;strong&gt;这段代码所在的整个组件树&lt;/strong&gt;,而 AI 大多数时候只看到你贴过去的那几行。&lt;/p&gt;

&lt;p&gt;于是就有了下面这 6 个几乎每天都能在 AI 生成的 PR 里看到的坏味道。每一个我都给出真实的对比代码,你合并前扫一眼就能看出来。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="1. 把渲染时能算的东西塞进 useEffect"&gt;1. 把渲染时能算的东西塞进 useEffect&lt;/h2&gt;
&lt;p&gt;这是 AI 生成 React 代码里&lt;strong&gt;最普遍&lt;/strong&gt;的坏味道,没有之一。&lt;/p&gt;
&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;OrderList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFiltered&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredOrders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setFiltered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredOrders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredOrders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;合计: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;三层问题:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;多渲染一轮&lt;/strong&gt;。orders 变 → 组件渲染 (拿到旧 total/filtered) → useEffect 跑 → setState → 再渲染一次。用户能感知的白屏/闪一下,很多来源于此。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;state 和 props 会脱同步&lt;/strong&gt;。如果哪天你多加一个 setFiltered 的分支忘了同步 total,数据就错了。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;依赖数组稍微写错就是死循环&lt;/strong&gt;。AI 写这类代码经常忘依赖或多依赖。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;
&lt;p&gt;派生数据&lt;strong&gt;直接在渲染阶段算&lt;/strong&gt;,不要 state,也不要 effect:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;OrderList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;合计: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 filter 真的很贵 (比如上万条 + 复杂计算),再考虑 &lt;code&gt;useMemo&lt;/code&gt;。&lt;strong&gt;先别急着优化&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;看到 AI 生成的 useEffect,第一个问自己:"这个逻辑,能不能直接写在 return 上面?" 大多数情况都能。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="2. 把 props 复制到 useState"&gt;2. 把 props 复制到 useState&lt;/h2&gt;&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看上去很合理:表单要能编辑,所以得有 state。&lt;/p&gt;
&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;useState(user.name)&lt;/code&gt; 里的 &lt;code&gt;user.name&lt;/code&gt; &lt;strong&gt;只在组件第一次挂载时被读一次&lt;/strong&gt;。之后父组件传入新的 user,&lt;code&gt;name&lt;/code&gt; 也不会更新。&lt;/p&gt;

&lt;p&gt;这个 bug 特别隐蔽——本地开发切换用户能看到,但 AI 写完你跑一遍单个用户流程,PR 就过了。&lt;/p&gt;

&lt;p&gt;上线之后一切换用户,表单显示上一个用户的数据,老板会问:"你测过没?"&lt;/p&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;明确表单是"受控还是非受控"&lt;/strong&gt;。两种解:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. 完全受控,state 在父组件&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nl"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; 
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; 
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;B. 内部 state,但要用 key 强制重挂载&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserForm&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一切换 user.id,React 会销毁旧组件重新创建,state 也会用新的 initial value。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;看到 &lt;code&gt;useState(props.xxx)&lt;/code&gt;,九成是错的。要么把 state 提上去,要么用 key 隔离。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="3. useEffect 里 fetch,不处理竞态"&gt;3. useEffect 里 fetch,不处理竞态&lt;/h2&gt;&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你能一眼看出问题吗?&lt;/p&gt;
&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;用户快速点击不同的用户 A → B → C,fetch 会&lt;strong&gt;按顺序发出&lt;/strong&gt;,但&lt;strong&gt;返回顺序不一定&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;如果 A 的请求走网络慢,C 已经回来了显示了 C 的名字,然后 A 的响应姗姗来迟——&lt;strong&gt;页面会突然变回 A 的数据&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;这不是理论,这是每一个做过用户列表页的前端都栽过的坑。AI 几乎从不主动处理。&lt;/p&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;
&lt;p&gt;用 &lt;code&gt;AbortController&lt;/code&gt; 或 stale flag:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AbortError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Skeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者更省心,&lt;strong&gt;直接用数据请求库&lt;/strong&gt;:SWR、React Query、TanStack Query 都自带竞态处理。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;useEffect 里但凡出现异步,cleanup 函数一定要写。没写就是坏味道。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="4. 列表 key 用 index"&gt;4. 列表 key 用 index&lt;/h2&gt;&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写这一行时 AI 甚至不会犹豫。&lt;/p&gt;
&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;当列表&lt;strong&gt;顺序变化&lt;/strong&gt;、&lt;strong&gt;中间插入&lt;/strong&gt;、&lt;strong&gt;删除&lt;/strong&gt;时,React 会用 key 去匹配前后两次渲染的元素。用 index 做 key,等于告诉 React:"第一位永远是第一位"——但你换了内容它认不出来。&lt;/p&gt;

&lt;p&gt;后果:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;列表项里如果有 &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;,用户输入到一半,你在上面插入一项,焦点就跑了&lt;/li&gt;
&lt;li&gt;列表项如果是带内部 state 的组件,state 会串位&lt;/li&gt;
&lt;li&gt;动画/transition 会错乱&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;
&lt;p&gt;用&lt;strong&gt;数据本身的稳定 id&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListItem&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果数据真的没 id,前端可以在拿到数据时用 &lt;code&gt;crypto.randomUUID()&lt;/code&gt; 或自增计数补一个,&lt;strong&gt;但要保证同一个数据永远拿同一个 id&lt;/strong&gt;——不能每次渲染新生成。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;看到 &lt;code&gt;key={index}&lt;/code&gt; &lt;code&gt;key={i}&lt;/code&gt; &lt;code&gt;key={idx}&lt;/code&gt;,直接怀疑。除非这个列表&lt;strong&gt;永远不会重排、不会插入删除、不会有内部 state&lt;/strong&gt;——才 100% 安全。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="5. 内联对象 / 函数,搭配 memo 组件 = memo 失效"&gt;5. 内联对象 / 函数,搭配 memo 组件 = memo 失效&lt;/h2&gt;&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #eee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看上去合理:子组件 memo 了,应该优化了。&lt;/p&gt;
&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;style={{ padding: 8 }}&lt;/code&gt; 和 &lt;code&gt;onClick={() =&amp;gt; ...}&lt;/code&gt; &lt;strong&gt;每次渲染都是新的引用&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; 默认用 &lt;code&gt;Object.is&lt;/code&gt; 做浅比较,新旧引用不等 → memo 直接失效 → 每次父组件渲染,所有 Row 都重渲染。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;你以为你优化了,其实一点没优化,还多了个浅比较的开销。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;
&lt;p&gt;内联对象提到外面 (如果是纯静态的):&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rowStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #eee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Row&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowStyle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意:让 Row 内部生成 &lt;code&gt;() =&amp;gt; onClick(rowId)&lt;/code&gt; 才能保证 &lt;code&gt;onClick&lt;/code&gt; 是稳定引用。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;看到 &lt;code&gt;React.memo&lt;/code&gt; 出现,立即扫一眼调用处的 props——如果传的是 &lt;code&gt;{...}&lt;/code&gt;、&lt;code&gt;[...]&lt;/code&gt;、&lt;code&gt;() =&amp;gt; ...&lt;/code&gt;,memo 直接白包。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="6. useMemo / useCallback 无脑加"&gt;6. useMemo / useCallback 无脑加&lt;/h2&gt;
&lt;p&gt;这条和上一条正好相反——&lt;strong&gt;AI 也经常反过来滥用 memo&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="AI 常见写法"&gt;AI 常见写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;三行代码,两个 hook。&lt;/p&gt;
&lt;h3 id="为什么坏"&gt;为什么坏&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; 和 &lt;code&gt;useCallback&lt;/code&gt; &lt;strong&gt;本身有成本&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;每次渲染都要跑依赖数组的浅比较&lt;/li&gt;
&lt;li&gt;React 内部要维护一个额外的记忆槽&lt;/li&gt;
&lt;li&gt;代码可读性直线下降&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一个字符串拼接,&lt;strong&gt;直接计算比 useMemo 快十倍&lt;/strong&gt;。给 button 传的 onClick 也不是 memo 组件,useCallback 完全没意义。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;滥用 memo 的代码,通常比不加 memo 更慢——因为该做的事情没少做,还多做了一层浅比较。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="正确写法"&gt;正确写法&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;只在下面两种情况才加 memo&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;计算真的贵 (比如上万条数据的 filter/sort/reduce)&lt;/li&gt;
&lt;li&gt;值/函数&lt;strong&gt;要作为 prop 传给 memo 组件&lt;/strong&gt;,或者作为 useEffect/useMemo 的依赖&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;除此之外——&lt;strong&gt;不加就是对的&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="判断标准"&gt;判断标准&lt;/h3&gt;
&lt;p&gt;看到 useMemo/useCallback,反问一句:"如果去掉它,哪里会重新计算/重渲染?" 答不上来,就删掉。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="最后:一份合并前 60 秒 checklist"&gt;最后:一份合并前 60 秒 checklist&lt;/h2&gt;
&lt;p&gt;如果你没时间读完全文,把下面这段贴到你的 Code Review 模板里:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;□ useEffect 里的逻辑,能不能挪到渲染阶段?
□ useState(props.xxx) 出现了吗?出现就是错。
□ useEffect 里的 fetch,有没有 AbortController 或 cleanup?
□ 列表 key 是不是稳定 id?不是就改。
□ React.memo 组件的 props,有没有内联对象/函数/数组?
□ useMemo/useCallback,如果删掉会怎样?说不上来就删。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;六个问题,合并前扫一眼一分钟搞定。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="一句话总结"&gt;一句话总结&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;AI 生成的 React 代码,语法都对,但 React 不是纯粹语法。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;它是一套"什么时候该干什么、什么时候该什么都不干"的判断力。AI 看不到你的组件树、看不到用户如何交互、看不到线上的性能数据——这些判断,现在还得你来做。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;用 AI 写代码不丢人,合并前不看 AI 写的什么,才丢人。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>193577746</author>
      <pubDate>Thu, 16 Jul 2026 21:53:41 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7779</link>
      <guid>https://beta.w2solo.com/topics/7779</guid>
    </item>
    <item>
      <title>About GWP LAW GROUP - California Financial Fraud and Asset Recovery Attorneys</title>
      <description>&lt;p&gt;Experienced Legal Representation for Complex Financial Disputes&lt;/p&gt;

&lt;p&gt;GWP LAW GROUP is a California-based law firm focused on providing legal solutions for individuals, businesses, and organizations facing complex financial disputes. With extensive experience in financial fraud matters, asset recovery, investment-related disputes, and cross-border financial challenges, our firm helps clients understand their legal options and take strategic steps to protect their financial interests.&lt;/p&gt;

&lt;p&gt;Financial disputes often involve complicated transactions, multiple parties, and significant documentation. At GWP LAW GROUP, we combine legal knowledge, investigative insight, and personalized strategies to help clients address challenging financial matters with confidence.&lt;/p&gt;

&lt;p&gt;20 Years of Legal Experience Serving Clients Across California&lt;/p&gt;

&lt;p&gt;For more than 20 years, GWP LAW GROUP has provided professional legal support for clients dealing with complex financial issues. Our experience allows us to analyze cases from multiple perspectives, including legal procedures, financial records, transaction histories, and dispute resolution strategies.&lt;/p&gt;

&lt;p&gt;Every financial case has unique circumstances. Our attorneys take the time to understand each client’s situation, identify key legal issues, and develop solutions based on the specific goals and needs of the client.&lt;/p&gt;

&lt;p&gt;Through years of handling financial-related legal matters, we have developed a comprehensive approach focused on clear communication, careful case evaluation, and efficient legal representation.&lt;/p&gt;

&lt;p&gt;Dedicated Financial Fraud Legal Support&lt;/p&gt;

&lt;p&gt;Financial fraud cases can involve misleading transactions, unauthorized activities, investment-related concerns, or complex financial arrangements. These cases often require detailed investigation and a strong understanding of both legal and financial factors.&lt;/p&gt;

&lt;p&gt;GWP LAW GROUP provides legal guidance for clients involved in financial fraud disputes by helping them:&lt;/p&gt;

&lt;p&gt;Review financial transactions and related documents
Understand available legal options
Evaluate potential recovery strategies
Protect their legal rights throughout the process
Pursue appropriate dispute resolution methods&lt;/p&gt;

&lt;p&gt;Our approach focuses on building a clear understanding of the facts and developing practical legal strategies designed around each client’s circumstances.&lt;/p&gt;

&lt;p&gt;Asset Recovery and Financial Loss Solutions&lt;/p&gt;

&lt;p&gt;Recovering lost assets requires careful analysis, strategic planning, and knowledge of financial systems. GWP LAW GROUP assists clients with asset recovery matters by examining available information, identifying potential recovery pathways, and providing legal support throughout the process.&lt;/p&gt;

&lt;p&gt;Our team works with clients to address challenges involving financial losses, disputed assets, and complex transactions. By combining legal experience with investigative techniques, we help clients better understand their options and make informed decisions.&lt;/p&gt;

&lt;p&gt;Supporting Individuals Businesses and International Clients&lt;/p&gt;

&lt;p&gt;Financial disputes can affect individuals, companies, investors, and organizations across different regions. GWP LAW GROUP provides legal services for both domestic and international clients who need assistance navigating complex financial matters.&lt;/p&gt;

&lt;p&gt;Our firm understands that cross-border financial disputes may involve additional challenges, including different jurisdictions, transaction structures, and communication requirements. We provide tailored legal guidance to help clients manage these complexities effectively.&lt;/p&gt;

&lt;p&gt;A Client-Focused Approach to Legal Representation&lt;/p&gt;

&lt;p&gt;At GWP LAW GROUP, we believe effective legal representation begins with understanding our clients’ concerns. We prioritize transparent communication, thorough case analysis, and personalized legal strategies.&lt;/p&gt;

&lt;p&gt;Our attorneys work closely with clients to explain legal processes, evaluate potential solutions, and provide guidance throughout each stage of a case.&lt;/p&gt;

&lt;p&gt;Whether addressing financial fraud concerns, investment disputes, or asset recovery matters, we remain committed to delivering professional and reliable legal support.&lt;/p&gt;

&lt;p&gt;Why Choose GWP LAW GROUP&lt;/p&gt;

&lt;p&gt;Clients choose GWP LAW GROUP because of our:&lt;/p&gt;

&lt;p&gt;Extensive Legal Experience&lt;/p&gt;

&lt;p&gt;With two decades of experience, our team understands the complexities involved in financial disputes and recovery-related cases.&lt;/p&gt;

&lt;p&gt;Strategic Case Analysis&lt;/p&gt;

&lt;p&gt;We carefully evaluate financial records, legal issues, and available options to develop effective strategies.&lt;/p&gt;

&lt;p&gt;Personalized Legal Solutions&lt;/p&gt;

&lt;p&gt;Every client and case is different. We provide customized approaches based on individual circumstances and objectives.&lt;/p&gt;

&lt;p&gt;Professional and Transparent Communication&lt;/p&gt;

&lt;p&gt;We keep clients informed and provide clear explanations throughout the legal process.&lt;/p&gt;

&lt;p&gt;Protecting Your Financial Rights With Experienced Legal Guidance&lt;/p&gt;

&lt;p&gt;Financial disputes can create significant challenges, but having experienced legal support can help clients better understand their options and move forward with confidence.&lt;/p&gt;

&lt;p&gt;GWP LAW GROUP provides professional legal assistance for financial fraud, asset recovery, investment loss, and complex financial dispute matters throughout California and beyond.&lt;/p&gt;

&lt;p&gt;With decades of experience and a commitment to client-focused representation, our attorneys are prepared to provide strategic legal solutions designed to protect your financial rights and interests.&lt;/p&gt;</description>
      <author>mobei2025</author>
      <pubDate>Thu, 16 Jul 2026 20:09:01 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7778</link>
      <guid>https://beta.w2solo.com/topics/7778</guid>
    </item>
    <item>
      <title>那个凌晨三点的账单，让我重新理解了 AI 成本</title>
      <description>&lt;p&gt;这是一篇不太像技术文章的反思。作为一个带技术团队十多年的老兵，我以为自己对"成本"两个字是有概念的。直到 AI 时代给了我一次结结实实的教育。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;一、CFO 的连环拷问&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;今年 Q1 的财务复盘会上，CFO 把一沓报表摔在桌上。&lt;/p&gt;

&lt;p&gt;"谁能告诉我，为什么 AI 相关的支出比去年同期翻了将近四倍？"&lt;/p&gt;

&lt;p&gt;会议室里安静得能听见空调声。&lt;/p&gt;

&lt;p&gt;"不是问你们花了多少，"她顿了顿，"我是问，这些钱分别是谁花的、花在什么上了、值不值？"&lt;/p&gt;

&lt;p&gt;三个问题，我一个都答不上来。&lt;/p&gt;

&lt;p&gt;我只知道研发部门申请了几个模型的 API，市场部门有人在使用 AI 写文案，客服系统也接入了智能对话。但具体到每个部门的消耗量、不同模型的使用比例、哪些调用是有效的哪些是浪费的，我完全没概念。&lt;/p&gt;

&lt;p&gt;更尴尬的是，这些费用分散在五六个不同的供应商账单里，有些是走公司信用卡，有些是员工个人垫付再报销，还有些是通过第三方中转购买的，连合规发票都凑不齐。&lt;/p&gt;

&lt;p&gt;那天晚上我翻来覆去睡不着。不是因为钱本身——公司不是花不起这个钱——而是因为我突然意识到，我们对待 AI 成本的态度，像极了二十年前中小企业对待 IT 支出的态度：粗放、模糊、事后算账。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;二、Token 不是成本，是生产资料&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;过去几个月，我慢慢想明白了一件事。&lt;/p&gt;

&lt;p&gt;以前企业买软件，是一次性采购。买一套 Oracle，多少钱合同里写得清清楚楚。买一台服务器，资产入库，折旧五年。成本是确定的、可预测的。&lt;/p&gt;

&lt;p&gt;但 Token 不一样。&lt;/p&gt;

&lt;p&gt;Token 是生产资料，和工厂的电力、物流的燃油是一个性质。你每调用一次，就在消耗一次。今天用得多，成本就高；明天用得少，成本就低。问题是，这个"用得多"和"用得少"，在企业里几乎处于完全失控的状态。&lt;/p&gt;

&lt;p&gt;我做过一个粗略的统计：我们公司每天大概有上万次大模型调用，其中有多少是重复提问？有多少是用顶级模型回答了本可以用便宜模型解决的简单问题？有多少是因为代码 Bug 导致的无效重试？&lt;/p&gt;

&lt;p&gt;答案是：不知道。&lt;/p&gt;

&lt;p&gt;不知道，才是最贵的。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三、找网关的过程，也是理清思路的过程&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我决定要解决这个问题的第一时间，其实没想上网关。&lt;/p&gt;

&lt;p&gt;我先是让团队写了个简单的调用日志系统，记录每次调用的模型、Token 数、调用方。做了一个月，发现数据是有了，但光有数据没用——没有预算管控，没有自动熔断，没有成本分摊，日志就只是日志。&lt;/p&gt;

&lt;p&gt;然后我又让团队尝试对接各个供应商的账单 API，想自动汇总。结果发现各家格式不统一，有些供应商根本不提供细粒度的账单接口。就算汇总出来了，还是没法和业务部门的实际使用对应上。&lt;/p&gt;

&lt;p&gt;折腾了将近一个月，团队一个资深工程师跟我说了一句话："领导，我们这是在重复造轮子。"&lt;/p&gt;

&lt;p&gt;他推给我一个产品：魔芋的 MAI Gateway。说是一个企业级的 AI 网关，但最让他印象深刻的不是网关本身，而是它内置的一套叫 FinAPI 的体系。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;四、FinAPI 到底解决了什么&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;说实话，一开始我对"FinAPI"这个名字是有点抵触的。听起来像是又一个造出来的概念。&lt;/p&gt;

&lt;p&gt;但深入了解之后，我发现它解决的是非常实在的问题。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;首先是统一治理。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;所有模型的调用，不管是公有云 API 还是本地部署的模型，全部走一个入口。每个部门、每个项目、每个用户，都在同一个体系下有独立的配额和权限。再也不用面对"这个 Key 是谁的、那个账单归哪个部门"这种灵魂拷问了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;然后是成本透明。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FinAPI 的核心理念是：每一枚 Token 都要能追溯到具体的部门、项目、甚至具体的使用者。网关自动记录每一次调用的完整链路，月底生成的不是一张糊涂账，而是一份按组织架构分层的成本报表。&lt;/p&gt;

&lt;p&gt;我第一次拿着这份报表去找 CFO 的时候，她愣了一下，说："终于有个能说清楚的了。"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;最后是成本优化。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这不是简单的"砍预算"。网关通过智能路由、语义缓存、上下文压缩这些技术手段，在保证业务效果的前提下，把无效消耗打掉。我们实际跑下来的数据：同样的业务量，Token 成本降低了接近一半。&lt;/p&gt;

&lt;p&gt;一半是什么概念？如果一家中型企业每年 AI 支出是几百万，这一半就是几百万的利润。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;五、从成本中心到竞争力&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;接入网关三个月后，我最大的感受不是"省钱了"，而是"终于能管理了"。&lt;/p&gt;

&lt;p&gt;管理意味着什么？意味着我可以做预算了。每个季度给各部门分配 AI 预算，花超了系统会自动熔断，花到 80% 会预警。意味着我可以做 ROI 评估了。市场部的文案生成花了多少 Token、产出了多少内容、带来了多少线索，终于可以放在一起看了。&lt;/p&gt;

&lt;p&gt;更深一层想，AI 成本管理这件事，迟早会从"有没有"变成"好不好"。&lt;/p&gt;

&lt;p&gt;两家竞品公司，用同样的模型做同样的事，一家花 100 万，一家花 60 万，那 40 万的差距就是利润空间。当 AI 真正成为企业的生产要素，成本治理能力就是核心竞争力。&lt;/p&gt;

&lt;p&gt;工业时代，会管机器的企业活得久。云计算时代，会管云资源的企业活得好。AI 时代，会管 Token 的企业，才有底气说自己在真正落地 AI。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;六、写在最后&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果你现在问我，企业用 AI 最重要的是什么？我的答案已经变了。&lt;/p&gt;

&lt;p&gt;一年前我会说"模型能力"。现在我会说"治理能力"。&lt;/p&gt;

&lt;p&gt;模型能力决定了你能做什么，治理能力决定了你能做多久。&lt;/p&gt;

&lt;p&gt;当然，工具只是工具，关键还是管理意识的转变。希望我的这次"被教育"的经历，能给正在经历同样困惑的你一点启发。&lt;/p&gt;</description>
      <author>lsraas100</author>
      <pubDate>Thu, 16 Jul 2026 16:26:05 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7777</link>
      <guid>https://beta.w2solo.com/topics/7777</guid>
    </item>
    <item>
      <title>+86 注册 Telegram 省短信费的实操记录</title>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tgclient.github.io/telegram-client" rel="nofollow" target="_blank" title=""&gt;👉👉👉登录纸飞机的入口，+86、苹果都能解决👈👈👈&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;简单说几个我亲测能用的方法：&lt;/p&gt;

&lt;p&gt;接码平台 — sms-activate、5sim，租号收验证码，几毛到几块不等。注意选"Telegram"专用号，通用号容易被风控。注册完建议立刻换绑或开启 2FA。&lt;/p&gt;

&lt;p&gt;虚拟号长期方案 — Google Voice 最稳但难搞，TextNow 免费但要定期登录保号。Talkatone 也可以，但 iOS 限制多。&lt;/p&gt;

&lt;p&gt;已有设备曲线救国 — 如果你有 iPad 或旧手机已经登录了 Telegram，新手机可以通过"添加设备"直接扫码进入，完全跳过短信验证这步。这是最容易被忽略但最省事的方法。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/quyb63232/9095b500-b64e-4d57-9d03-6559a8f64468.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;实体卡兜底 — giffgaff、KnowRoaming 这类海外预付卡，几十块买一张，收码稳得一匹，适合当主力号用。&lt;/p&gt;

&lt;p&gt;最后提醒：Telegram 对 +86 的风控逻辑经常变，上个月能用的接码平台这个月可能就不行了，多备几个渠道比较保险。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tgclient.github.io/telegram-client" rel="nofollow" target="_blank" title=""&gt;👉👉👉登录纸飞机的入口，+86、苹果都能解决👈👈👈&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>quyb63232</author>
      <pubDate>Thu, 16 Jul 2026 15:47:27 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7776</link>
      <guid>https://beta.w2solo.com/topics/7776</guid>
    </item>
    <item>
      <title>出海业务网络解决方案：Novproxy 全品类住宅代理应用与选型指南</title>
      <description>&lt;p&gt;一、引言&lt;/p&gt;

&lt;p&gt;随着海外数据采集、跨境电商多店铺运营、海外社媒矩阵、广告核验、品牌风控监测等业务持续扩张，住宅代理已经成为出海企业必不可少的网络基础设施。不少从业者在采购代理时缺乏清晰规划，仅依据单价做选择，将单一代理产品混用在账号运营与大规模爬虫场景中，进而引发账号批量封禁、爬虫频繁触发人机验证、月度流量成本失控等一系列经营损耗。&lt;/p&gt;

&lt;p&gt;市面上住宅代理分为动态住宅代理、静态 ISP 独享代理、无限流量包月代理三大主流品类，三者 IP 资源来源、计费规则、风控适配能力存在本质区别，不存在通用型代理能够适配全部业务。Novproxy 作为一站式海外住宅代理服务商，搭建了分层独立的 IP 资源池，完整覆盖三类代理产品，能够匹配不同出海业务的差异化需求。本文结合产品底层参数与实战落地经验，全面解析三类代理的功能、适用边界，同时输出标准化选型与运维方案，为爬虫开发、跨境运营人员提供落地参考。&lt;/p&gt;

&lt;p&gt;二、Novproxy 三大住宅代理产品详解&lt;/p&gt;

&lt;p&gt;（一）动态住宅代理：轻量化短期数据采集工具&lt;/p&gt;

&lt;p&gt;动态住宅代理的 IP 资源均来自全球真实家庭宽带与无线网络，平台储备 1.5 亿级纯净民用 IP 池，覆盖 195 个国家及地区，支持国家、城市、ASN、邮编五级精准定位，可满足分区域市场调研、区域性竞品数据抓取需求。&lt;/p&gt;

&lt;p&gt;产品提供两种工作模式，用户可按需切换：轮换模式会在每一次请求更换全新 IP，适合大批量高频抓取，规避单一 IP 访问限制；粘性会话模式可自定义 1 至 120 分钟固定 IP 时长，适配需要临时登录页面、短时交互采集的场景。&lt;/p&gt;

&lt;p&gt;计费采用阶梯按量收费模式，流量长期有效不清零，无强制包月开销，采购体量越大单价越低，大批量采购单价低至 0.5 美元每 GB。新人可选择小额流量套餐完成线路测试，试错成本极低。&lt;/p&gt;

&lt;p&gt;该产品存在明确使用限制：IP 会自动轮换，长期登录店铺、支付、社媒账号会产生异地访问记录，极易触发平台风控，严禁用于账号长期运维。&lt;/p&gt;

&lt;p&gt;适配业务：电商竞品价格周期性采集、搜索引擎区域 SEO 排名监测、海外广告真实性抽检、短期行业市场调研、公开舆情轻量抓取。&lt;/p&gt;

&lt;p&gt;（二）静态 ISP 独享住宅代理：多账号防关联专用方案&lt;/p&gt;

&lt;p&gt;静态 ISP 住宅代理由海外正规运营商直供原生固定民用 IP，实行单人独享机制，订阅周期内 IP 地址保持不变，全程不限流量。该产品融合数据中心低延迟与住宅 IP 高匿名两大优势，是多账号矩阵运营的核心工具。&lt;/p&gt;

&lt;p&gt;遵循一号一 IP 的使用规范，能够实现账号网络环境物理隔离，从底层杜绝多账号共用网段带来的批量封号风险。平台保障 99.9% 线路可用率，支持 7×24 小时不间断挂机养号，提供 7 天、30 天、90 天多种订阅周期，批量采购可最高享受 25% 折扣，单 IP 起步价格仅 3.8 美元。&lt;/p&gt;

&lt;p&gt;使用过程中存在两项约束：禁止多个账号共用单条静态 IP，丧失隔离防护效果；不建议使用静态 IP 执行高频大规模爬虫抓取，海量请求会快速消耗 IP 信誉，连带绑定账号被平台限制。&lt;/p&gt;

&lt;p&gt;适配业务：亚马逊、Shopee、eBay 等跨境电商多店铺运营、TikTok、Facebook 等长期品牌社媒主号运维、PayPal 等境外支付账户日常登录与资金操作。&lt;/p&gt;

&lt;p&gt;（三）无限流量包月代理：高并发全天候自动化集群配套&lt;/p&gt;

&lt;p&gt;无限流量代理采用固定月度收费模式，无流量使用上限，不存在超额扣费问题，支持数千线程同步高并发请求，分为带宽、端口两套独立使用模式。&lt;/p&gt;

&lt;p&gt;带宽模式按照采购带宽规格计费，系统随机分配全球住宅 IP，无需限定特定国家，适合短视频、高清商品图等大容量素材长期抓取；端口模式按照端口数量阶梯定价，支持自主筛选目标国家 IP，可自定义 3 至 30 分钟粘性会话，端口采购规模越大单端口日均成本越低。对于每月消耗百 GB 乃至 TB 级流量的自动化业务，对比按量计费的动态代理，长期使用可节省 50% 以上运营成本。&lt;/p&gt;

&lt;p&gt;该产品短板为固定月度支出，仅用于日均流量极少的小型测试场景会造成带宽闲置，拉高整体运维成本。&lt;/p&gt;

&lt;p&gt;适配业务：短视频、高清素材批量抓取、全天候全域广告投放巡检、品牌线上侵权自动监测、长期 SEO 实时监控、大规模社媒自动化脚本集群。&lt;/p&gt;

&lt;p&gt;三、Novproxy 平台核心综合优势&lt;/p&gt;

&lt;p&gt;分层隔离 IP 资源池&lt;/p&gt;

&lt;p&gt;动态采集 IP、静态账号 IP、无限流量采集 IP 三套资源池完全独立，不会相互混用，平台定期清洗黑名单违规 IP，避免爬虫抓取行为污染店铺账号 IP 信誉，大幅降低验证码拦截与账号封禁概率。&lt;/p&gt;

&lt;p&gt;全协议兼容，开发接入便捷&lt;/p&gt;

&lt;p&gt;完整支持 HTTP、HTTPS、SOCKS5 主流协议，后台管理面板可一键生成账密配置与标准化 API 链接，无缝对接各类爬虫框架、指纹隔离浏览器；提供账号密码、IP 白名单双重安全校验，防止代理资源被盗用，企业可分配子账号精细化管控团队权限。&lt;/p&gt;

&lt;p&gt;全球分布式稳定线路&lt;/p&gt;

&lt;p&gt;全球多区域节点布局，平均请求延迟控制在 0.6 秒以内，高并发、长时间挂机场景断线率极低，减少爬虫脚本重试逻辑的开发维护成本。&lt;/p&gt;

&lt;p&gt;分层灵活定价，适配各类用户&lt;/p&gt;

&lt;p&gt;针对个人开发者、中小团队、大型企业设置梯度定价，新手小额动态套餐可低成本完成线路测试；静态 IP、无限流量套餐批量采购、长期订阅均有阶梯优惠；大型企业可定制专属私有独立 IP 池，独享线路满足高风控品牌业务需求。&lt;/p&gt;

&lt;p&gt;完善配套技术服务&lt;/p&gt;

&lt;p&gt;配备 7×24 小时在线技术客服，针对脚本对接、多账号隔离部署、线路故障排查提供实时指导，配套完整使用文档与落地案例，降低团队学习成本。&lt;/p&gt;

&lt;p&gt;四、标准化选型落地规范&lt;/p&gt;

&lt;p&gt;短期轻量化数据采集、无长期账号登录需求&lt;/p&gt;

&lt;p&gt;优先选择动态住宅代理，按需消耗流量，无固定包月闲置成本；新站点、新脚本上线前统一使用小额动态套餐测试站点拦截强度，确认 IP 质量稳定后再扩大采集规模。&lt;/p&gt;

&lt;p&gt;跨境店铺、社媒账号矩阵运营，核心需求防关联、长期稳定网络&lt;/p&gt;

&lt;p&gt;统一部署静态 ISP 独享 IP，严格执行一号一 IP 规范；账号运营线路与爬虫采集线路完全分开，使用两套代理与浏览器，禁止交叉混用。&lt;/p&gt;

&lt;p&gt;7×24 小时不间断自动化任务、月度大流量高并发业务&lt;/p&gt;

&lt;p&gt;选用无限流量包月套餐，有效压缩长期流量运营成本；端口模式可按业务需求划分国家分组，适配多区域同步采集任务。&lt;/p&gt;

&lt;p&gt;五、总结&lt;/p&gt;

&lt;p&gt;出海业务中，代理 IP 不只是简单切换网络的工具，更是平衡风控安全与运营成本的核心基础设施。多数团队遭遇账号封禁、采集受阻、账单超支等问题，根源并非 IP 质量不佳，而是代理产品与业务场景错配。&lt;/p&gt;

&lt;p&gt;Novproxy 完整覆盖动态、静态 ISP、无限流量三类住宅代理，具备独立分层 IP 池、低延迟全球线路、便捷开发接入、灵活分层定价等多重优势，一站式满足个人爬虫开发者、中小跨境团队、大型企业自动化集群的全场景出海网络需求。&lt;/p&gt;

&lt;p&gt;业务落地建议遵循先测试、后批量采购的原则，先用小额套餐验证线路适配性，再根据自身流量规模、账号体量选择对应代理产品，兼顾业务稳定性与项目预算，最大限度降低出海网络运维风险。&lt;/p&gt;</description>
      <author>Novproxy6</author>
      <pubDate>Thu, 16 Jul 2026 15:32:01 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7775</link>
      <guid>https://beta.w2solo.com/topics/7775</guid>
    </item>
    <item>
      <title>用这套社交论坛圈子源码做个付费圈子小程序，一个月多赚 3 万</title>
      <description>&lt;p&gt;要靠这套付费圈子小程序实现‌月多赚 3 万‌，核心不是靠源码本身，而是把「产品定位 + 流量转化 + 后端留存」的闭环跑通，用最低的成本撬动精准付费用户，以下是可直接落地的实操方案，帮你把源码变成稳定的现金流工具：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;多客圈子系统：&lt;/strong&gt;明确基于 ThinkPHP6 + UniApp 开发，前端全开源，功能完整，集成付费入圈，有详细的搭建教程&lt;/p&gt;
&lt;h2 id="一个成熟的付费圈子系统，通常包括以下核心模块："&gt;一个成熟的付费圈子系统，通常包括以下核心模块：&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;圈子管理：&lt;/strong&gt;这是核心。支持用户自主创建公开或付费圈子，圈主/管理员可以设置入圈费用、管理成员和内容，用户支付后自动解锁。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;内容与互动：&lt;/strong&gt;用户可以发布图文、视频等多种形式的帖子，并支持点赞、评论、收藏、分享等功能，形成良好的社区讨论氛围。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;用户与会员体系：&lt;/strong&gt;支持微信一键登录和手机号登录。通过会员等级、积分签到等功能激励用户活跃，并为付费内容设置门槛。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;付费与变现机制：&lt;/strong&gt;除了付费入圈，还支持帖子付费阅读、打赏、虚拟礼物、会员订阅等，形成完整的商业闭环。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IM 即时通讯：&lt;/strong&gt;方便圈子内的成员进行一对一私聊或群聊，是社交产品增强用户粘性的关键功能
&lt;img src="https://img.way2solo.com/photo/DKqiqi/13833e14-c4e5-4ea4-807c-6e59547362b3.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="🛠️ 搭建流程概览"&gt;🛠️ 搭建流程概览&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;准备工作：&lt;/strong&gt;购买一台云服务器（建议 4 核 8G 配置起步）和一个已备案的域名，并申请好微信小程序的 AppID。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;部署后端：&lt;/strong&gt;将 ThinkPHP 6 源码上传至服务器，导入数据库，并修改.env 配置文件，填入你的数据库、Redis 等信息即可。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;编译前端：&lt;/strong&gt;用 HBuilderX 打开 UniApp 前端源码，在 siteinfo.js 或类似配置文件中将接口地址修改为你的后端域名，然后点击 “发行”，即可一键生成微信小程序代码包。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;上线运营：&lt;/strong&gt;将代码包提交至微信公众平台审核。请注意，小程序上线需要申请 “社交 - 社区/论坛” 类目，并可能需要准备相关资质。
&lt;img src="https://img.way2solo.com/photo/DKqiqi/e16ed92f-de5c-4c30-b8d0-69503d8eb6e3.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="适用领域"&gt;适用领域&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一、行业圈子：&lt;/strong&gt;您可以使用在你的行业领域，让本行业的有交流和联系的圈子。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;二、地方圈子：&lt;/strong&gt;您可以使用在本地区，运营地方性的综合圈子或论坛，搭配商城频道，可以做类似美团的本地到店消费，搭配交友频道可做本地社交。搭配圈子可做信息发布类。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;三、纯社交圈子：&lt;/strong&gt;搭配交友频道，和语聊房间频道可运营娱乐社交类 APP，可实现 VIP 充值盈利和虚拟礼物主播分成模式，&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;四、游戏开黑圈子：&lt;/strong&gt;搭配语聊与交友。可作为游戏开黑组队和代练模式交易。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;五、兴趣圈子：&lt;/strong&gt;你所熟悉的某个兴趣点专注领域，种草社区结合商城系统。直接种草和电商结合。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;六、活动搭子类：&lt;/strong&gt;为用户提供活动组局、搭子、商家活动发布类产品。
&lt;img src="https://img.way2solo.com/photo/DKqiqi/0e29478e-5d7d-4227-a795-5228a43a26e9.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="查看演示及源码获取地址！！！"&gt;&lt;a href="https://www.51duoke.cn/games/?id=2" rel="nofollow" target="_blank" title=""&gt;查看演示及源码获取地址！！！&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/DKqiqi/c596c831-663b-4269-9d2f-dd65b03e741a.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>DKqiqi</author>
      <pubDate>Thu, 16 Jul 2026 14:15:23 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7774</link>
      <guid>https://beta.w2solo.com/topics/7774</guid>
    </item>
    <item>
      <title>成品来袭！专为三角洲行动打造的代练下单系统，源码交付快速搭建</title>
      <description>&lt;p&gt;随着《三角洲行动》持续火爆，“跑刀摸金”“全装护航”“撞车定制” 等游戏服务需求呈现爆发式增长。然而，大量代练工作室和个人打手仍深陷微信群接单的泥潭——订单信息零散易遗漏、资金往来缺乏保障、客户资源随时可能流失。一套专为《三角洲行动》打造的成品代练下单系统，正在成为游戏服务创业者实现正规化运营的关键路径。
&lt;img src="https://img.way2solo.com/photo/DK11/849d5385-788c-4bf8-a93b-2d4197e34899.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
一、为什么选择成品源码？——省时、省力、省成本&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;无需从零开发，7-15 天快速上线
从零开发一套完整的代练系统，涉及前后端开发、数据库设计、支付对接、多端适配等多个环节，动辄需要 3-5 个月时间和数十万研发成本。而成品源码方案，完整打包交付 UniApp 多端前端、PHP 业务后端、总管理后台，无加密源码、支持私有化部署，7-15 天即可完成部署上线，成本仅需数千元。&lt;/li&gt;
&lt;li&gt;源码交付，数据自主可控
与使用第三方代练平台不同，成品源码采用私有化部署方案，所有用户数据、订单记录、资金流水全部存储在你自己的服务器上，无第三方数据泄露风险，平台收益 100% 归运营者所有。&lt;/li&gt;
&lt;li&gt;一套代码，多端覆盖
基于 UniApp 跨端开发框架，一套代码即可编译发布为：微信小程序（承接私域流量）、微信公众号 H5、PC 管理后台、iOS/Android 独立 App，所有端账号互通、数据实时同步。
&lt;img src="https://img.way2solo.com/photo/DK11/30a26dcb-0741-4851-9fe8-74f7baeb0132.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/DK11/cc3b40c2-3a50-4426-a235-8b051aa770a1.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
二、系统技术架构：成熟稳定，开箱即用
这套系统采用当前行业主流的轻量级技术栈，兼顾开发效率与部署稳定性：
&lt;img src="https://img.way2solo.com/photo/DK11/5ebf0a0c-ddd2-4802-a40a-c881bd0edc73.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
三、核心功能模块：跑通代练全流程
系统围绕五端角色构建完整业务闭环：&lt;/li&gt;
&lt;li&gt;老板端（玩家）
三步快捷下单——选游戏→选服务→在线支付
支持指定心仪打手、等待抢单或客服派单三种模式
实时追踪订单进度，查看验收截图
在线沟通、评价维权&lt;/li&gt;
&lt;li&gt;打手端（服务者）
抢单大厅实时刷新，支持多条件筛选
个人主页展示战绩、完成单量、好评率，打造个人 IP
需实名认证 + 缴纳保证金方可接单，防止跑单
佣金自动结算、提现管理&lt;/li&gt;
&lt;li&gt;客服端（运营枢纽）
与双方实时沟通、手动派单
审核打手完成截图、处理异常纠纷订单
智能回复 + 人工客服，24 小时维护秩序&lt;/li&gt;
&lt;li&gt;管事端（团队管理者）
通过邀请码招募并管理下线打手
获取团队佣金分成，适合发展裂变团队&lt;/li&gt;
&lt;li&gt;工作室端（公会/俱乐部）
入驻认证后，拥有独立邀请码体系
可内部自主分配订单并进行财务结算
&lt;img src="https://img.way2solo.com/photo/DK11/45fa780d-a82f-490f-a750-473e9159a8f7.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/DK11/204f6eed-38d5-43e9-88ba-67ed44143f4a.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
总结
与其在别人的平台上被抽成、被限流，不如现在就自建一套属于自己的代练平台。这套专为《三角洲行动》打造的一站式代练下单系统，采用成熟的 ThinkPHP6+UniApp 技术栈，覆盖老板、打手、客服、管事、工作室五端协同，源码交付、支持二次开发、多端适配，是游戏服务创业者与技术团队的理想选择——快速搭建私有平台，掌控数据与利润，业务拓展的自由度全在自己手上。&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>DK11</author>
      <pubDate>Thu, 16 Jul 2026 13:40:48 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7773</link>
      <guid>https://beta.w2solo.com/topics/7773</guid>
    </item>
    <item>
      <title>游戏公会/自媒体变现利器：把私域流量变成持续现金流：陪玩护航系统小程序搭建</title>
      <description>&lt;p&gt;本文档旨在全面介绍陪玩系统的产品功能、技术架构与落地部署方案。&lt;/p&gt;

&lt;p&gt;系统前端采用 UniApp（Vue 2.0），一套代码多端运行，覆盖 H5、服务号、小程序及 App；后端基于 ThinkPHP 6，架构清晰，上手门槛低。系统提供完整源码，支持二次开发，仅通过域名授权保障正版。&lt;/p&gt;

&lt;p&gt;功能上，系统覆盖从选人、下单、接单到完单评价的全流程，同时支持陪玩自定义服务定价、语音房间、社交广场、派单抢单等核心玩法。本文将从技术栈、功能结构、所需资质、部署流程及常见问题五个方面进行说明，帮助您快速了解并上手该产品。&lt;/p&gt;

&lt;p&gt;多客陪玩护航系统 · 产品技术与功能白皮书&lt;/p&gt;

&lt;p&gt;🛠 一、 技术架构与交付标准&lt;/p&gt;

&lt;p&gt;前端框架：基于 UniApp (Vue 2.0) 开发，支持一键打包 H5、微信服务号、微信小程序及安卓/iOS 双端 App，全场景覆盖。&lt;/p&gt;

&lt;p&gt;后端框架：采用 ThinkPHP 6，架构轻量、逻辑清晰，运维与二次开发门槛极低。&lt;/p&gt;

&lt;p&gt;交付模式：提供完整开源源码，绑定域名授权防翻版，支持深度二次开发与个性化定制。&lt;/p&gt;

&lt;p&gt;🔄 二、 核心交易逻辑（双模式闭环）&lt;/p&gt;

&lt;p&gt;系统支持两种主流下单路径，完美契合不同用户消费习惯：&lt;/p&gt;

&lt;p&gt;模式一（社交优先）：选人 → 试听 → 选项目 → 下单 → 接单 → 完单 → 结单 → 评价&lt;/p&gt;

&lt;p&gt;模式二（效率优先）：选服务 → 看人/听声 → 下单 → 接单 → 完单 → 结单 → 评价&lt;/p&gt;

&lt;p&gt;💡 差异化优势：打破传统统一定价！支持每位陪玩 自主申请服务项目并自定义定价，灵活适配不同等级与品类，实现利润分层。&lt;/p&gt;

&lt;p&gt;📱 三、 终端功能矩阵&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;首页流量中枢&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkrjkf/108bb0d6-b18d-4b88-93bd-ae5bf40f4449.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;

&lt;p&gt;数据看板：关注、粉丝、获赞数实时同步。&lt;/p&gt;

&lt;p&gt;虚拟资产：金豆（系统币）充值与消费体系。&lt;/p&gt;

&lt;p&gt;业务管理：订单管理、收入明细（打赏 + 服务）、服务管理、陪陪认证、个人主页及派单设置。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;前端页面展示（支持 H5+ 小程序 +app 多端同步）
&lt;img src="https://img.way2solo.com/photo/dkrjkf/58dce025-ab47-4e82-8966-79936e020842.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/5221be9d-6034-4f1d-9a0d-2aee31bba4f1.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/a74714f5-af15-40eb-a569-3513484f0130.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📋 四、 部署与资质指南&lt;/p&gt;

&lt;p&gt;🔑 所需资质清单&lt;/p&gt;

&lt;p&gt;营业执照（个体/企业）：用于账号认证及小程序备案。&lt;/p&gt;

&lt;p&gt;法人信息：实名认证必需。&lt;/p&gt;

&lt;p&gt;微信商户号（个体/对公）：用于平台交易结算。&lt;/p&gt;

&lt;p&gt;邮箱/手机号：平台注册与登录凭证。&lt;/p&gt;

&lt;p&gt;⚙️ 环境准备要求&lt;/p&gt;

&lt;p&gt;服务器：用于运行系统环境。&lt;/p&gt;

&lt;p&gt;域名：需完成 ICP 备案后访问。&lt;/p&gt;

&lt;p&gt;微信服务号：需企业认证。&lt;/p&gt;

&lt;p&gt;微信小程序：需认证并申请「互联网娱乐」类目备案。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkrjkf/9e84647c-b593-4f22-8a1e-f60c4c904d29.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;❓ 五、 常见问题 FAQ&lt;/p&gt;

&lt;p&gt;Q1：搭建陪玩小程序需要什么主体资质？&lt;/p&gt;

&lt;p&gt;需具备营业执照（企业或个体户），用于注册和认证所需的微信账号。&lt;/p&gt;

&lt;p&gt;Q2：小程序如何通过审核？&lt;/p&gt;

&lt;p&gt;需申请微信「互联网娱乐」类目。要求营业执照经营范围包含 “动漫游戏开发” 或 “互联网游戏服务” 等相关内容（具体以微信官方最新规则为准）。&lt;/p&gt;

&lt;p&gt;Q3：源码如何部署？&lt;/p&gt;

&lt;p&gt;附赠详细部署文档，推荐使用宝塔面板可视化操作。核心步骤：建站 → 上传源码 → 配置 .env 数据库 → 导入 SQL 数据。&lt;/p&gt;

&lt;p&gt;💡
&lt;img src="https://img.way2solo.com/photo/dkrjkf/cba70c12-440d-45bb-a348-519f943545c7.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>dkrjkf</author>
      <pubDate>Thu, 16 Jul 2026 10:45:58 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7772</link>
      <guid>https://beta.w2solo.com/topics/7772</guid>
    </item>
    <item>
      <title>一对一音视频交友软件开发的互动模式增强了社交性和隐私性/交友 APP 开发搭建部署</title>
      <description>&lt;p&gt;一、 增强社交性的互动模式设计&lt;/p&gt;

&lt;p&gt;传统的 “一对多” 直播难以满足用户深度交流的需求，一对一视频交友通过沉浸式体验解决了这一痛点。&lt;/p&gt;

&lt;p&gt;‌沉浸式音视频互动‌&lt;/p&gt;

&lt;p&gt;‌高清低延迟通话‌：基于 RTC（实时通信）技术，确保在弱网环境下也能保持流畅的 1V1 视频连接，减少卡顿带来的社交尴尬。&lt;/p&gt;

&lt;p&gt;‌美颜与特效‌：集成实时美颜、滤镜及虚拟背景功能，提升用户自信心，降低出镜心理门槛。&lt;/p&gt;

&lt;p&gt;‌多元化破冰机制‌&lt;/p&gt;

&lt;p&gt;‌兴趣智能匹配‌：利用大数据算法，根据用户年龄、地理位置、兴趣标签（如音乐、旅行）进行精准推荐，并在视频界面展示共同话题提示，避免冷场。&lt;/p&gt;

&lt;p&gt;‌虚拟礼物系统‌：在视频过程中发送鲜花、跑车等虚拟礼物，触发全屏特效。这既增加了趣味性，也是平台主要的变现手段。&lt;/p&gt;

&lt;p&gt;‌互动游戏‌：内置真心话大冒险、你画我猜等轻量级小游戏，缓解初次见面的紧张感。
&lt;img src="https://img.way2solo.com/photo/v-septhana8/2f3fc95d-1579-4b99-8f6b-38e42d8c71aa.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/v-septhana8/71f26b41-b364-44e3-b9c3-5714e19bc8fd.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;二、 强化隐私性与安全防护&lt;/p&gt;

&lt;p&gt;交友软件的信任基石是隐私保护，需从技术和管理两方面构建安全屏障。&lt;/p&gt;

&lt;p&gt;‌数据隐私保护‌&lt;/p&gt;

&lt;p&gt;‌防截屏/录屏机制‌：Android 端禁止截屏和录屏，iOS 端检测到截屏行为时向对方发送警告通知，防止隐私泄露。&lt;/p&gt;

&lt;p&gt;‌阅后即焚与加密存储‌：支持消息 “阅后即焚”，聊天记录在服务器端加密存储并设置自动清理周期。&lt;/p&gt;

&lt;p&gt;‌内容合规与风控‌&lt;/p&gt;

&lt;p&gt;‌AI 实时审核‌：接入第三方云服务商（如阿里云、腾讯云）的内容安全 API，对视频流、音频流、图片及文本进行实时监测，自动拦截涉黄、涉暴及广告内容。&lt;/p&gt;

&lt;p&gt;‌真人实名认证‌：强制要求用户进行人脸识别活体检测，确保 “真人真身”，从源头遏制虚假账号和诈骗行为。&lt;/p&gt;

&lt;p&gt;‌举报与拉黑‌：提供便捷的举报入口，用户遇到骚扰可立即切断连接，后台需建立快速响应的人工客服机制。
&lt;img src="https://img.way2solo.com/photo/v-septhana8/52d5eff6-2efc-4f19-894f-adba761d2e7f.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;三、 APP 开发搭建与技术架构&lt;/p&gt;

&lt;p&gt;采用前后端分离架构，确保多端数据互通且维护成本低。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;技术选型推荐&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;‌前端开发‌：&lt;/p&gt;

&lt;p&gt;‌框架‌：‌UniApp‌。基于 Vue 语法，一套代码可编译发布为 iOS App、Android App、微信小程序及 H5，极大降低多端开发成本。&lt;/p&gt;

&lt;p&gt;‌组件‌：在视频通话页面调用原生 live-pusher (推流) 和 live-player (拉流) 组件，保证性能。&lt;/p&gt;

&lt;p&gt;‌后端开发‌：&lt;/p&gt;

&lt;p&gt;‌语言/框架‌：‌ThinkPHP 6‌ PHP 适合快速迭代。&lt;/p&gt;

&lt;p&gt;‌即时通讯‌：‌GatewayWorker‌ (PHP) 或 ‌Netty‌ (Java) 构建 WebSocket 长连接服务，处理 IM 信令。&lt;/p&gt;

&lt;p&gt;‌数据库‌：‌MySQL‌ 存储用户资料、订单、关系链；‌Redis‌ 缓存热点数据、在线状态及匹配队列。&lt;/p&gt;

&lt;p&gt;‌音视频服务‌：&lt;/p&gt;

&lt;p&gt;‌SDK 集成‌：建议集成 ‌腾讯云 TRTC‌ 或 ‌阿里云 RTC‌。自研 WebRTC 底层难度大，商业 SDK 提供完善的弱网对抗、回声消除能力，并按用量付费，初期成本低。&lt;/p&gt;</description>
      <author>v-septhana8</author>
      <pubDate>Thu, 16 Jul 2026 10:42:53 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7771</link>
      <guid>https://beta.w2solo.com/topics/7771</guid>
    </item>
    <item>
      <title>为什么越来越多的大厂抛弃 MCP，转向 CLI？</title>
      <description>&lt;h2 id="为什么越来越多的大厂抛弃MCP，转向CLI？"&gt;为什么越来越多的大厂抛弃 MCP，转向 CLI？&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;一个 AI 圈最打脸的故事：新造的"万能协议"正在被一个 50 岁的老东西取代，而且输得毫无悬念。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="先说结论（给不想看长文的朋友）"&gt;先说结论（给不想看长文的朋友）&lt;/h2&gt;
&lt;p&gt;MCP（Model Context Protocol）是 Anthropic 2024 年底推出的"AI 连接万物"标准。但到了 2026 年，越来越多开发者和公司正悄悄放弃它，回到一个更古老、更简单、更可靠的东西——&lt;strong&gt;命令行 CLI。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;为什么？因为 CLI 简单到极致：文本进、文本出，没有 JSON 握手、没有状态管理、没有协议兼容性问题。而你装好系统就有的 git、npm、docker、kubectl，就是最好的 AI 工具连接层。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;明天你就能用&lt;/strong&gt;：打开 Claude Code 或 Cursor，别去配 MCP Server，直接用自然语言描述需求，让它调用系统 CLI 工具——比你费劲配一套 MCP 靠谱 100 倍。&lt;/p&gt;
&lt;h2 id="一、这故事要从一个"&gt;一、这故事要从一个"万能翻译官"说起&lt;/h2&gt;
&lt;p&gt;2024 年冬天，Anthropic 发布了 MCP。全称 Model Context Protocol —— 模型上下文协议。&lt;/p&gt;

&lt;p&gt;它的愿景很美好：做一个"AI 世界的万国翻译官"。你的 AI Agent 想查数据库？MCP 帮你连接。想调 API？MCP 帮你翻译。想读写文件？MCP 帮你处理。理论上，有了 MCP，AI 就能跟外部世界的一切通信了。&lt;/p&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;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;翻译官把你的话转成 JSON 格式再传给对方：{"intent": "question", "tone": "curious", "content": "这个 API 怎么调用？"}—— 这叫&lt;strong&gt;JSON-RPC 消息编码。&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;如果翻译官突然卡住了，你不知道是它听错了，还是翻译错了，还是对方理解错了。日志打出来 500 行，你一行行翻。 —— 这叫&lt;strong&gt;状态机调试地狱。&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这就是 MCP 的现实。它设计得很"完备"，但完备的代价是复杂。而复杂，在工程世界里是最大的敌人。&lt;/p&gt;
&lt;h2 id="二、CLI：50岁的"&gt;二、CLI：50 岁的"插座哲学"&lt;/h2&gt;
&lt;p&gt;那命令行 CLI（Command Line Interface）呢？&lt;/p&gt;

&lt;p&gt;它的哲学跟 MCP 完全相反。MCP 是"我什么都能懂，只要你按我的规矩来"。CLI 是"我什么都不懂，我只有一个规矩：你给我文本，我给你文本"。&lt;/p&gt;

&lt;p&gt;还是用比喻——&lt;/p&gt;

&lt;p&gt;MCP 是万国翻译官。CLI 是标准插座。&lt;/p&gt;

&lt;p&gt;你往插座上插台灯，它亮。插风扇，它转。插电视机，它播。插座不知道你是谁，也不在乎你是什么规格——只要你对准 220V、输出文本到 stdout/接收文本从 stdin，它就工作。&lt;/p&gt;

&lt;p&gt;git log → 给你 commit 记录。
npm test → 给你测试结果。
curl api.example.com → 给你 HTTP 响应。&lt;/p&gt;

&lt;p&gt;没有握手。没有 JSON。没有状态机。没有协议版本兼容问题。&lt;/p&gt;

&lt;p&gt;Unix/Linux 的命令行在服务器上已经跑了整整 50 年。这 50 年里，服务器崩过、操作系统换过、CPU 架构变过、编程语言迭代过——但 /bin/sh 的&lt;strong&gt;文本流模型&lt;/strong&gt;从来没有崩过。&lt;/p&gt;
&lt;h2 id="三、五个维度看清CLI为什么赢"&gt;三、五个维度看清 CLI 为什么赢&lt;/h2&gt;
&lt;p&gt;让我们把 MCP 和 CLI 放在五个维度上对比。你会发现，CLI 的胜利不是偶然——&lt;/p&gt;
&lt;h3 id="维度一：开发成本"&gt;维度一：开发成本&lt;/h3&gt;&lt;table class="table table-bordered table-striped"&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;CLI&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;写一个 Server/工具&lt;/td&gt;
&lt;td&gt;需要理解 JSON-RPC、状态管理、协议规范。新手第一周还配不齐环境。&lt;/td&gt;
&lt;td&gt;写个脚本，输出到 stdout。新手五分钟搞定。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;生态规模&lt;/td&gt;
&lt;td&gt;~200+ 个 MCP Server（增长速度慢，维护成本高）&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;数十万个&lt;/strong&gt;CLI 工具（整个 Unix/Linux/Node/Python 生态系统）&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;h3 id="维度二：调试难度"&gt;维度二：调试难度&lt;/h3&gt;
&lt;p&gt;MCP 出错了：500 行 JSON 堆栈，嵌套三层的错误对象，你要用 jq 或者专门工具去解析。&lt;/p&gt;

&lt;p&gt;CLI 出错了："&lt;strong&gt;command not found&lt;/strong&gt;" → 你没装这个工具。"&lt;strong&gt;Permission denied&lt;/strong&gt;" → 加 sudo。"&lt;strong&gt;Connection refused&lt;/strong&gt;" → 服务没启动。&lt;/p&gt;

&lt;p&gt;你花在 MCP 调试上的时间，够你写十个 CLI 脚本。&lt;/p&gt;
&lt;h3 id="维度三：可靠性"&gt;维度三：可靠性&lt;/h3&gt;
&lt;p&gt;CLI 的可靠性已经被时间验证过了。grep 从 1970 年代 ** 走到今天，中间经历了多少次操作系统大版本升级？零次因为"协议变更"导致 grep 不能用。&lt;/p&gt;

&lt;p&gt;MCP 呢？协议还在快速迭代。今天你的 MCP Server 跑得好好的，明天一更新 SDK，Agent 就不能用了。你骂谁？骂自己没事找事。&lt;/p&gt;
&lt;h3 id="维度四：可组合性（这是CLI的核武器）"&gt;维度四：可组合性（这是 CLI 的核武器）&lt;/h3&gt;
&lt;p&gt;Unix 哲学有一条核心原则："&lt;strong&gt;Do one thing and do it well&lt;/strong&gt;" —— 做好一件事，做到极致，然后组合。&lt;/p&gt;

&lt;p&gt;CLI 的组合武器叫&lt;strong&gt;管道符&lt;/strong&gt; |：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 .# 找出代码仓库里所有TODO注释，按类型统计
2. git diff HEAD~10 | grep "+.*TODO" | sort | uniq -c | sort -rn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个工具的结果，直接喂给下一个工具。没有任何中间格式转换。没有任何协议适配。&lt;/p&gt;

&lt;p&gt;MCP 做不到这一点。每个 MCP Server 是一个孤岛——它的输出必须经过 Host 层解析，再以 JSON 传给另一个 Server。这中间损耗的不只是性能，还有灵活性。&lt;/p&gt;
&lt;h3 id="维度五：维护成本"&gt;维度五：维护成本&lt;/h3&gt;
&lt;p&gt;git、npm、docker、kubectl、aws、gh —— 这些 CLI 工具你装好系统就有，或者在官方源一键安装。它们有专门的团队维护，你不需要多写一行代码。&lt;/p&gt;

&lt;p&gt;MCP Server 呢？你写的，你维护。你团队写的，你团队维护。没人会帮你升级协议兼容性，没人会帮你修状态机 bug。你养了个技术债，还要每月还利息。&lt;/p&gt;
&lt;h2 id="四、战场实况：谁在放弃MCP？"&gt;四、战场实况：谁在放弃 MCP？&lt;/h2&gt;
&lt;p&gt;先别管我怎么说，看事实——&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;（Anthropic 自家的 AI 编程工具）：底层大量使用系统 CLI 调用，git、npm、eslint 这些全走 CLI，不是 MCP。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt;：Agent 模式直接运行终端命令——npm run dev、python test.py、git diff，全是原生 CLI 调用。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windsurf&lt;/strong&gt;（Codeium 的 AI IDE）：正在从 MCP 集成转向更直接的 CLI 工具链集成。社区里已经有大量讨论关于"MCP 的维护成本太高了"。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI Codex CLI&lt;/strong&gt;：2025 年发布，整个设计哲学就是"用自然语言驱动 CLI 工具"。它甚至没有 MCP，直接走 subprocess。&lt;/p&gt;

&lt;p&gt;你品品：连&lt;strong&gt;Anthropic&lt;/strong&gt;自己的旗舰产品都在大量用 CLI，MCP 还有什么理由说自己是"唯一标准"？&lt;/p&gt;
&lt;h2 id="五、明天就能用的三个实战"&gt;五、明天就能用的三个实战&lt;/h2&gt;
&lt;p&gt;好了，理论说了这么多。现在告诉你&lt;strong&gt;明天打开电脑就能做的事：&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="场景一：用Claude Code自动创建PR"&gt;场景一：用 Claude Code 自动创建 PR&lt;/h3&gt;
&lt;p&gt;打开 Claude Code，在对话里说：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"帮我把最近 5 个 commit 总结一下，写成一个 PR 描述，然后创建 PR。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude Code 会自动：&lt;/p&gt;

&lt;p&gt;1.执行 git log --oneline -5 → 拿到 commit 记录&lt;/p&gt;

&lt;p&gt;2.用 LLM 理解每个 commit 做了什么 → 生成 PR 描述&lt;/p&gt;

&lt;p&gt;3.执行 gh pr create --title "..." --body "..." → 创建 PR&lt;/p&gt;

&lt;p&gt;全程没有 MCP。全是 CLI。你不需要配任何东西。&lt;/p&gt;
&lt;h3 id="场景二：用Cursor分析日志"&gt;场景二：用 Cursor 分析日志&lt;/h3&gt;
&lt;p&gt;在 Cursor 的 Agent 聊天里说：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"帮我分析 app.log 文件里所有包含 'error' 的行，按小时统计数量。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cursor 会自动：&lt;/p&gt;

&lt;p&gt;1.执行 grep error app.log → 拿到所有 error 行&lt;/p&gt;

&lt;p&gt;2.用时间戳正则提取小时&lt;/p&gt;

&lt;p&gt;3.执行 sort | uniq -c → 统计频率&lt;/p&gt;

&lt;p&gt;4.返回给你一个清晰的分布表&lt;/p&gt;
&lt;h3 id="场景三：构建你自己的AI+CLI工作流"&gt;场景三：构建你自己的 AI+CLI 工作流&lt;/h3&gt;
&lt;p&gt;你不需要等工具官方支持某个功能。你只要确保你的工具有 CLI，AI 就能操作它。&lt;/p&gt;

&lt;p&gt;-Jira？用 jira-cli&lt;/p&gt;

&lt;p&gt;-Kubernetes？用 kubectl&lt;/p&gt;

&lt;p&gt;-AWS？用 aws-cli&lt;/p&gt;

&lt;p&gt;-Notion？用 notion-cli（第三方）&lt;/p&gt;

&lt;p&gt;核心原则：任何有 CLI 的工具，都是 AI 的原生工具。你不需要它支持 MCP。&lt;/p&gt;
&lt;h2 id="六、所以，MCP真的死了吗？"&gt;六、所以，MCP 真的死了吗？&lt;/h2&gt;
&lt;p&gt;倒也不是。&lt;/p&gt;

&lt;p&gt;MCP 在某些场景下仍然有价值——特别是&lt;strong&gt;需要双向实时通信&lt;/strong&gt;的复杂交互场景。比如 AI Agent 需要持续监控某个数据源的变化，或者需要跟浏览器做深度交互。&lt;/p&gt;

&lt;p&gt;但问题在于：&lt;strong&gt;MCP 当初被定位为"通用标准"，而现在它正在变成一个"专用协议"&lt;/strong&gt;。它没有成为 AI 连接万物的 USB-C——它变成了一个需要特定适配器的专用接口。
而 CLI，这个"原始"的文本流协议——因为太简单，所以不可替代；因为太古老，所以绝对可靠；因为太通用，所以万物皆可连。&lt;/p&gt;

&lt;p&gt;## 七、最后一句话&lt;/p&gt;

&lt;p&gt;当所有人都在造新轮子的时候，最聪明的人回到了那个最老的轮子。&lt;/p&gt;

&lt;p&gt;AI 时代的"通用协议"，不叫 MCP——叫 /bin/sh。&lt;/p&gt;

&lt;p&gt;感兴趣的可以了解一下我整理的表单，//jsj.top/f/o38ijj&lt;/p&gt;

&lt;p&gt;作者：web_Leon&lt;/p&gt;

&lt;p&gt;来源：稀土掘金&lt;/p&gt;</description>
      <author>coderwamgh</author>
      <pubDate>Thu, 16 Jul 2026 10:00:34 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7770</link>
      <guid>https://beta.w2solo.com/topics/7770</guid>
    </item>
    <item>
      <title>我给 5 个网站做了个关键词排名监控，一个月光 API 不到 $3</title>
      <description>&lt;p&gt;我手上跑着 5 个 side project，每个都想做点 SEO。但市面上能用的排名追踪工具全是给 agency 准备的——Ahrefs $99/月起，SEMrush $130/月起。对一个还在 MVP 阶段的小项目来说，这笔钱投出去肉疼。&lt;/p&gt;

&lt;p&gt;不投的话，我完全不知道"react server components 教程"这种我花了 3 周打底的关键词，到底有没有从第 47 名爬到第 30 名。Google Search Console 数据滞后 2-3 天，免费工具又只能看自家站。&lt;/p&gt;

&lt;p&gt;所以我给自己写了一个小工具。每天早上 8 点自动跑一遍我关心的关键词，存到 SQLite 里。一共写了不到 80 行 Python。下面是过程和成本。&lt;/p&gt;
&lt;h2 id="第一次尝试：又去爬 Google"&gt;第一次尝试：又去爬 Google&lt;/h2&gt;
&lt;p&gt;老规矩，先试试自己爬。Python 写个 &lt;code&gt;requests&lt;/code&gt;，模拟浏览器，parse HTML。20 分钟后 IP 被 ban。&lt;/p&gt;

&lt;p&gt;换个方案：用 Playwright 跑 headless Chrome，加住宅代理。一个月下来：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;代理费用：$0.005/次 × 每天 100 次 × 30 天 = $15&lt;/li&gt;
&lt;li&gt;维护时间：每周大概 2 小时调试（Google 改 selector 就崩一次）&lt;/li&gt;
&lt;li&gt;失败率：30% 左右&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这还没算上"我的网站突然被 Google 标记"的风险。一个小项目不值得冒这个险。&lt;/p&gt;
&lt;h2 id="试过的 SERP API"&gt;试过的 SERP API&lt;/h2&gt;
&lt;p&gt;我对比了四个 SERP API，按"独立开发者友好"程度排：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SerpApi&lt;/strong&gt;：$50/月，5000 次。功能全，但订阅制 + 月底清零，对低频使用不友好。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serper.dev&lt;/strong&gt;：$50/月，50000 次。比 SerpApi 单价低，但同样订阅 + 清零。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DataForSEO&lt;/strong&gt;：按次 $0.0006 起，但要签合同 + 预充值 + 月结。对个人开发者来说流程太重。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SerpBase&lt;/strong&gt;：$3 买 10,000 次搜索（Starter Boost），1 个月内有效。不用订阅，$10 以上的包不过期。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;$3 = 10,000 次搜索这个组合对我正合适。我每天只用 100 次左右，10,000 次能撑一个季度。&lt;/p&gt;
&lt;h2 id="实际接入：80 行 Python"&gt;实际接入：80 行 Python&lt;/h2&gt;
&lt;p&gt;我用 &lt;code&gt;/google/search&lt;/code&gt; 端点，1 次搜索 1 credit。核心代码：&lt;/p&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sqlite3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;

&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"你的 key"&lt;/span&gt;
&lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ranks.db"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_serp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"us"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"https://api.serpbase.dev/google/search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"X-API-Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"num"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"gl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"device"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"desktop"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"organic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_my_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"us"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_serp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;my_domain&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqlite3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"INSERT INTO ranks (date, keyword, domain, rank) VALUES (?, ?, ?, ?)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每天跑一次，把"哪个关键词、哪个网站、今天第几名"写进 SQLite。一个月下来我就有了一条完整曲线。&lt;/p&gt;
&lt;h2 id="成本核算"&gt;成本核算&lt;/h2&gt;
&lt;p&gt;我的实际用量：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 个网站 × 20 个关键词 = 100 个关键词&lt;/li&gt;
&lt;li&gt;每天 1 次 = 100 次/天&lt;/li&gt;
&lt;li&gt;30 天 = 3,000 次/月&lt;/li&gt;
&lt;li&gt;$0.30/1k 单价 = $0.90/月&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;实际上我没买按 $0.30 的 Enterprise 包——我用 $3 的 Starter Boost 撑了 3 个月（10,000 次 ÷ 3,000/月 ≈ 3 个月）。Boost 过期后我换 $10 的 Starter 包（20,000 次，$0.50/1k，不过期），又够跑半年。&lt;/p&gt;

&lt;p&gt;对独立开发者来说，这个成本结构才是友好的：先花 $3 试，跑通了再决定要不要升级。&lt;/p&gt;
&lt;h2 id="加个本地 SEO 模块"&gt;加个本地 SEO 模块&lt;/h2&gt;
&lt;p&gt;做了主流程之后，我又给其中一个本地服务类的 side project 加了地图排名监控。&lt;/p&gt;

&lt;p&gt;两个端点串着用：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;/google/maps/search&lt;/code&gt; 找商家（每次 2 credit）&lt;/li&gt;
&lt;li&gt;拿到 &lt;code&gt;feature_id&lt;/code&gt; 之后调 &lt;code&gt;/google/maps/detail&lt;/code&gt; 拿完整商家信息（每次 2 credit）&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_place&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"https://api.serpbase.dev/google/maps/search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"X-API-Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lng"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"zoom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s"&gt;"places"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_place_detail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feature_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"https://api.serpbase.dev/google/maps/detail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"X-API-Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"feature_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;feature_id&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s"&gt;"place"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lat&lt;/code&gt;/&lt;code&gt;lng&lt;/code&gt;/&lt;code&gt;zoom&lt;/code&gt; 这三个参数很重要——传了之后 SERP 会模拟"在这个坐标点附近搜"的结果，跟你从 Google Maps 网页端搜的体验一致。本地 SEO 不传坐标等于白搜。&lt;/p&gt;

&lt;p&gt;加这个模块之后，我的用量翻倍——但 $3 的额度还是撑得住。&lt;/p&gt;
&lt;h2 id="几个坑"&gt;几个坑&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;desktop vs mobile&lt;/strong&gt;：SERP 的桌面端和移动端排名差异巨大。我两个都查，desktop 用来看主关键词，mobile 用来看本地化结果（Google 移动端更偏本地包）。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Overview&lt;/strong&gt;：从 2025 年开始，越来越多的关键词会触发 &lt;code&gt;ai_overview&lt;/code&gt; 字段（Google 自己生成的 AI 总结）。我没把它当成一个排名——AI Overview 是抢流量的，不是抢排名的。我只追踪 organic。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP / 语言地区差异&lt;/strong&gt;：同一个关键词 &lt;code&gt;hl=en&amp;amp;gl=us&lt;/code&gt; 和 &lt;code&gt;hl=zh&amp;amp;gl=cn&lt;/code&gt; 出来的结果完全不同。我的 SaaS 是面向全球的，所以两个区都查。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter Boost 限制&lt;/strong&gt;：$3 包每月只能买一次，过期 1 个月。$10 以上不限次、永不过期。记清楚。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="一点感受"&gt;一点感受&lt;/h2&gt;
&lt;p&gt;我现在的方案：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;每天早上 8 点 cron 跑一次&lt;/li&gt;
&lt;li&gt;100 个关键词 + 20 个本地商家 = 120 次搜索&lt;/li&gt;
&lt;li&gt;一个月 3,600 次 = $1.08（按 $0.30/1k 单价算）&lt;/li&gt;
&lt;li&gt;实际花了 $3（Starter Boost），撑 3 个月&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;成本几乎可以忽略。关键是现在我每天都能看到自己的排名曲线，知道哪篇文章在涨、哪篇在掉、哪个关键词被 AI Overview 抢了流量。&lt;/p&gt;

&lt;p&gt;独立开发者做 SEO 的最大障碍不是"不懂"，是"看不到"。看不到就没法迭代。$3 起步的工具就能把这件事闭环了，比 $99/月的工具更适合早期项目。&lt;/p&gt;

&lt;p&gt;新手可以先用免费 100 次额度（注册就送，不用绑卡）验证自己的查询逻辑：&lt;a href="https://serpbase.dev/register" rel="nofollow" target="_blank"&gt;https://serpbase.dev/register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;剩下的就看你的网站到底要打什么关键词了。&lt;/p&gt;</description>
      <author>dodou88</author>
      <pubDate>Thu, 16 Jul 2026 08:23:37 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7769</link>
      <guid>https://beta.w2solo.com/topics/7769</guid>
    </item>
    <item>
      <title>《智能体三角模型白皮书》意图共鸣科技谈私有知识域与 AI 落地</title>
      <description>&lt;p&gt;你开了一家湘菜馆，给店里配了一个 AI 助手。这个 AI 助手很聪明，能处理各种咨询，也能回答常见问题。但第一天启用，你问它：“我们店今天有什么招牌菜？” 它愣住了。它不知道。&lt;/p&gt;

&lt;p&gt;它可以去网上搜，搜出来 “辣椒炒肉” 是湘菜经典。但你店里今天没进辣椒，做不了。它搜出来的信息，对你是没用的。&lt;/p&gt;

&lt;p&gt;你需要的，是一个 “懂你家店” 的 AI 系统。它知道厨房今天有什么菜，知道哪个菜利润高，知道老客户喜欢什么口味，知道哪个包厢的空调坏了、不能安排客人坐那里。&lt;/p&gt;

&lt;p&gt;这些信息，没有哪本教科书会写，没有哪个大模型能提前知道。只有你自己有。&lt;/p&gt;

&lt;p&gt;这就是 “私有知识域”。&lt;/p&gt;

&lt;p&gt;它不是 AI 从网上学来的通用知识，而是你自己输入给它的——你家店的地址、营业时间、菜单、价格、优惠活动、老客户偏好、品牌承诺、话术红线。这些东西，决定了 AI 是 “不熟悉你业务的通用工具” 还是 “真正懂你业务的专属工具”。&lt;/p&gt;

&lt;p&gt;私有知识域有几个核心特性。&lt;/p&gt;

&lt;p&gt;每家店都不一样。你家湘菜馆和我家美容院，给 AI 输入的数据完全不同。哪怕用的是同一个 AI 大脑、同一套交互规则，最后 AI 的表现也截然不同，因为你们的业务不一样。这就保证了你的 AI 是独一无二的，不是批发来的。&lt;/p&gt;

&lt;p&gt;你的数据只属于你。全程加密存放，物理隔离，平台看不到，也不能拿去做其他用途。在全球数据合规越来越严格的今天，数据主权清晰，你的核心业务资产不会外流。&lt;/p&gt;

&lt;p&gt;你家的菜单结构、优惠活动、话术风格，自己说了算，不是套一个模板就完事。同行业的通用内容可以复用标准模板，你的个性化业务信息独立录入，兼顾了部署效率和专属化需求。你想让 AI 怎么介绍菜品、怎么回答常见问题、怎么处理投诉，都可以按自己的规矩来。&lt;/p&gt;

&lt;p&gt;那私有知识域到底能干什么？举个例子。&lt;/p&gt;

&lt;p&gt;假设你是一家律所。你的 AI 助手如果只有通用知识，它只能回答 “什么是劳动仲裁”“法律条文怎么说”。但你需要它回答的是：“我们所处理劳动仲裁的收费标准是多少？”“王律师之前处理过类似的案子吗？”“客户问能不能分期付款，我们应该怎么回？” 这些，只有你的私有知识域里才有。&lt;/p&gt;

&lt;p&gt;再比如你是一家美容院。你的 AI 助手如果只有通用知识，它只能回答 “补水有什么好处”“什么是光子嫩肤”。但你需要它回答的是：“我们店现在有没有补水套餐的优惠？”“张女士上次做了深层清洁，这次该做什么项目合适？”“客户问能不能预约周六下午三点，我们还有空位吗？” 这些，也只有你的私有知识域里才有。&lt;/p&gt;

&lt;p&gt;没有私有知识域，AI 就是一个 “问啥答啥的通用机器人”。有了私有知识域，AI 才是 “真正懂你生意的专属工具”。&lt;/p&gt;

&lt;p&gt;这就是私有知识域的价值——让你的 AI 不再是路人甲。&lt;/p&gt;</description>
      <author>XinIRP</author>
      <pubDate>Wed, 15 Jul 2026 23:01:34 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7768</link>
      <guid>https://beta.w2solo.com/topics/7768</guid>
    </item>
    <item>
      <title>面试官让我优化一个卡死的表格，我打开 Claude 五秒重写——他放下咖啡问我要不要来当组长</title>
      <description>&lt;p&gt;上周去面试一家做 SaaS 的中厂，二面是一位四十出头的前端负责人。&lt;/p&gt;

&lt;p&gt;寒暄结束，他直接把笔记本转过来推到桌子中间：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"这是我们线上一个真实的报表页，10 万行数据，滚起来直接卡死。你帮我看看怎么优化。用什么工具都行。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;最后那半句他说得很平淡，我当时没多想。&lt;/p&gt;

&lt;p&gt;结果二十分钟后，他把咖啡杯往桌上一放，问了我一个我准备了整场面试都没想到的问题。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="一、题目本身：一个"&gt;一、题目本身：一个"教科书级"的坑&lt;/h2&gt;
&lt;p&gt;页面代码大概长这样（我做了脱敏改写）：&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ReportTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// rows.length ≈ 100_000&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;thead&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Select&lt;/span&gt; &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;statusOptions&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DatePicker&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatedAt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;td&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写过一年 React 的都能一眼看出问题：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;10 万行一次性渲染 → 首屏就是白屏 6-8 秒&lt;/li&gt;
&lt;li&gt;每行还挂着 &lt;code&gt;&amp;lt;Select&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;DatePicker&amp;gt;&lt;/code&gt; 这种带弹层的重组件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;key&lt;/code&gt; 没问题，但 diff 也扛不住 40 万个 DOM 节点&lt;/li&gt;
&lt;li&gt;滚动过程再触发 hover / active，浏览器直接躺平&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;搁在教科书里，标准优化路径也有三条：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;虚拟滚动（react-window / &lt;a href="/tanstack" class="user-mention" title="@tanstack"&gt;&lt;i&gt;@&lt;/i&gt;tanstack&lt;/a&gt;/react-virtual）&lt;/li&gt;
&lt;li&gt;时间切片渐进渲染（&lt;code&gt;startTransition&lt;/code&gt; / &lt;code&gt;requestIdleCallback&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;Canvas / 半 Canvas 渲染（AG Grid、Handsontable 那种）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;三种我都懂，但每种都有细节：单元格要不要支持编辑？行高是否等高？要不要支持多选？滚动过程能不能容忍占位闪一下？&lt;/p&gt;

&lt;p&gt;真让我在白板上写完再讲清楚三者的取舍——20 分钟够呛。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="二、我做了一件"&gt;二、我做了一件"面试大忌"的事&lt;/h2&gt;
&lt;p&gt;我抬头问了一句：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"您刚才说，用什么工具都行？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;面试官点头。&lt;/p&gt;

&lt;p&gt;于是我把自己的笔记本翻开，打开 Claude Code，把这段组件连同 &lt;code&gt;Row&lt;/code&gt; 类型、业务约束一起丢了进去，只写了一句：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"React 18 + TS。10 万行表格，每行 5 列，其中两列有 Select 和 DatePicker。产品要求可以滚动、可以点某一行进入详情、后期可能要支持行内编辑。给我三种优化方案，并解释在哪种交互需求下谁最合适。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;大概 4 秒之后，屏幕上刷出了三段方案。&lt;/p&gt;
&lt;h3 id="方案一：虚拟滚动（@user2/react-virtual）"&gt;方案一：虚拟滚动（&lt;a href="/tanstack" class="user-mention" title="@tanstack"&gt;&lt;i&gt;@&lt;/i&gt;tanstack&lt;/a&gt;/react-virtual）&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useVirtualizer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-virtual&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ReportTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parentRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rowVirtualizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useVirtualizer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;getScrollElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parentRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;estimateSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;overscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;parentRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rowVirtualizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTotalSize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rowVirtualizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getVirtualItems&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`translateY(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* row cells */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude 的注释里写：&lt;em&gt;"最通用、社区最成熟。等高行下开箱即用，行内编辑也没问题。缺点是 Select / DatePicker 这类弹层组件在滚出可视区时会被销毁，弹层里的选中态要托管到外层 state。"&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="方案二：时间切片渐进渲染"&gt;方案二：时间切片渐进渲染&lt;/h3&gt;&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ReportTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;visibleCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setVisibleCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visibleCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requestIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setVisibleCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cancelIdleCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;visibleCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visibleCount&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* cells */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;tbody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;table&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude 提示：&lt;em&gt;"首屏最快，DOM 结构最简单，SEO 友好。但滚到最底部要 10+ 秒才能加载完，用户拖滚动条会看到断层。适合'看不完但不能少'的报表——比如打印导出前的预览页。"&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="方案三：半 Canvas 渲染（AG Grid / 自研）"&gt;方案三：半 Canvas 渲染（AG Grid / 自研）&lt;/h3&gt;
&lt;p&gt;Claude 直接建议接第三方库，并给出了两条使用理由：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"如果表格未来要支持行内编辑、多选、复制粘贴、列拖拽——自己造轮子会一路踩坑。AG Grid 的 Community 版本免费够用，缺点是包体积 500KB+，且样式覆盖成本高。"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我把屏幕转向面试官。他没说话，只是往前挪了挪坐姿。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="三、真正让面试官愣住的，不是 AI 给的答案"&gt;三、真正让面试官愣住的，不是 AI 给的答案&lt;/h2&gt;
&lt;p&gt;我接着说：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"我倾向于方案一。因为您说了'后期可能要支持行内编辑'——Canvas 方案改起来太重，切片方案在编辑焦点跳出时会重排。虚拟滚动只要把弹层组件的开合状态提到外层就行。要不咱们跑一下 Performance 看看？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我把三种方案都在他们的测试环境跑了一遍，Chrome DevTools 打开 Performance。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;未优化：首屏 6.8 秒，滚动帧率 8 FPS&lt;/li&gt;
&lt;li&gt;方案一：首屏 320 ms，滚动稳定 60 FPS&lt;/li&gt;
&lt;li&gt;方案二：首屏 90 ms，但滚到底部要 12 秒&lt;/li&gt;
&lt;li&gt;方案三：首屏 480 ms，60 FPS，但 bundle 大了 480 KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;首屏时间从 6.8 秒压到 320 毫秒，快了 &lt;strong&gt;21 倍&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;面试官这时候放下了咖啡杯，问了我第一个"意外"的问题：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"你怎么判断把弹层 state 提到外层就够了？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我说：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"我没直接判断。Claude 给方案后我又追问了一次——'如果同一行的 Select 打开时用户滚出可视区，会发生什么？'它回答说组件会 unmount，弹层直接消失。所以我在方案一里加了一句：把 openId 提到父组件用 Portal 渲染弹层。这样滚出去也不会关。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;面试官盯着我看了两秒，问了第二个问题：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"你组里其他前端，也是这么用 AI 的吗？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我如实说：不是。大部分同事要么完全不用，要么直接把 AI 的答案 Ctrl+C Ctrl+V 提交。&lt;/p&gt;

&lt;p&gt;他"嗯"了一声，然后是第三个问题——就是那个让我离开会议室之后琢磨了一路的问题：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"我们前端组长下个月转岗。你要不要考虑一下这个位置？"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr&gt;
&lt;h2 id="四、我在地铁上想明白的事"&gt;四、我在地铁上想明白的事&lt;/h2&gt;
&lt;p&gt;回程地铁上我一直在想：他到底看中了什么？&lt;/p&gt;

&lt;p&gt;不是虚拟滚动。方案二方案三我都答得上来，任何一个高级前端都能。&lt;/p&gt;

&lt;p&gt;不是 AI。他们组里肯定有人 Claude、Cursor 都开着。&lt;/p&gt;

&lt;p&gt;想通之后我总结出三点，写在这里给同样在跳槽的朋友：&lt;/p&gt;
&lt;h3 id="1. 他看的是信息带宽，不是答题速度"&gt;1. 他看的是&lt;strong&gt;信息带宽&lt;/strong&gt;，不是&lt;strong&gt;答题速度&lt;/strong&gt;
&lt;/h3&gt;
&lt;p&gt;传统面试考察的是"你脑子里存了多少知识"。但当所有人脑子里都能调用同一个 AI 的时候，考察点就变成了"你能在单位时间内提出多好的问题"。&lt;/p&gt;

&lt;p&gt;我丢给 Claude 的那条 prompt 里有五个关键要素：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;技术栈（React 18 + TS）&lt;/li&gt;
&lt;li&gt;数据量级（10 万行 5 列）&lt;/li&gt;
&lt;li&gt;复杂组件（Select、DatePicker）&lt;/li&gt;
&lt;li&gt;交互约束（可滚动、可点击、可能要编辑）&lt;/li&gt;
&lt;li&gt;判断标准&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果我只写"帮我优化这个卡顿的表格"，Claude 给的答案就是水平线。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;面试官看到的其实是：这个人的 prompt 里，藏着五年前端经验。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="2. 他看的是验证能力，不是采纳能力"&gt;2. 他看的是&lt;strong&gt;验证能力&lt;/strong&gt;，不是&lt;strong&gt;采纳能力&lt;/strong&gt;
&lt;/h3&gt;
&lt;p&gt;我在讲方案时说过一句话："这是 Claude 给的，但我用 Performance 面板验证过了。"&lt;/p&gt;

&lt;p&gt;这句话之所以关键，是因为它划出了两类人：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;把 AI 输出当权威，直接提交&lt;/li&gt;
&lt;li&gt;把 AI 输出当同事的初稿，看完了再判断&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;后一种人，团队里其实不多。而这种人是能带团队的。&lt;/p&gt;
&lt;h3 id="3. 他看的是你怎么让 AI 干活，不是你会不会用 AI"&gt;3. 他看的是&lt;strong&gt;你怎么让 AI 干活&lt;/strong&gt;，不是&lt;strong&gt;你会不会用 AI&lt;/strong&gt;
&lt;/h3&gt;
&lt;p&gt;前端组长这个岗位在他心里对应的画像大概是：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"一个能把 AI 当放大器用的人，一个人的产出等于三个人。而且他知道什么时候不该信 AI——比如弹层脱离视口、比如包体积不能牺牲。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我在展示解题过程里，无意间把这两点都露出来了。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="五、给还在准备面试的前端"&gt;五、给还在准备面试的前端&lt;/h2&gt;
&lt;p&gt;如果你也在跳槽，尤其在中厂到大厂的过渡区间，几个我踩过之后的建议：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;能带电脑就带电脑。&lt;/strong&gt; 越来越多的公司允许现场用工具了。别怕面试官觉得你依赖 AI——他们在乎的是你怎么用。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;练习"提问"比练习"手写"回报大。&lt;/strong&gt; 手写 Promise、手写深拷贝、手写 EventEmitter，AI 三秒能解。但"给出三种方案 + 比较适用场景 + 结合数据量和交互约束"这种 prompt，得真练。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;每一次 AI 给答案后，都强迫自己追问一次"如果 X 前提不成立，会怎样"。&lt;/strong&gt; 例如：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;如果表格行高不等，虚拟滚动会怎样？&lt;/li&gt;
&lt;li&gt;如果用户网速慢，切片渲染的最后一屏会怎样？&lt;/li&gt;
&lt;li&gt;如果产品要打印全表，Canvas 方案怎么办？&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这是把 AI 的天花板变成你的地板的唯一方法。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;准备一段"我怎么用 AI"的故事。&lt;/strong&gt; 不是理论，是具体的一次协作过程。这段故事的价值，比你把 Fiber 原理背下来大得多。&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="尾声"&gt;尾声&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;2026 年了，考察前端的方式已经变了。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;变化不是"你会不会用 AI"，而是"你能不能带着 AI，做出一个人做不完的事"。&lt;/p&gt;

&lt;p&gt;面试官那天放下咖啡的那 2 秒，我大概能听见他脑子里在想什么：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"这人来了之后，我这个季度的排期能砍一半。"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;能被这么想，比手写十道八股都值钱。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>193577746</author>
      <pubDate>Wed, 15 Jul 2026 20:47:17 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7767</link>
      <guid>https://beta.w2solo.com/topics/7767</guid>
    </item>
    <item>
      <title>怎么做陪玩系统才能挣钱？0 基础可落地的完整盈利方案</title>
      <description>&lt;p&gt;很多人做陪玩平台不赚钱，真不是赛道不行。&lt;/p&gt;

&lt;p&gt;电竞陪玩、线上陪伴仍是高频、刚需、现金流稳的千亿赛道。做不起来，核心只有 3 个问题：
❌ 盈利模式单一，只靠抽成，利润薄；
❌ 没有裂变体系，花钱获客，留不住人；
❌ 系统不适配，结算混乱，运营无工具。&lt;/p&gt;

&lt;p&gt;赚钱靠的是：可复制盈利模型 + 成熟系统 + 自动裂变。
多客陪玩系统，预制全套赚钱逻辑，0 基础直接落地盈利。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkrjkf/83a98457-0cbf-4ff3-a3a3-4edbc201fc07.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;🔥 一、多元盈利结构，告别薄利&lt;/p&gt;

&lt;p&gt;订单抽成：全品类服务，阶梯定价、自动分账，稳定现金流。&lt;/p&gt;

&lt;p&gt;直播打赏：内置语音房，礼物分成撬动高利润增量。&lt;/p&gt;

&lt;p&gt;会员增值：月/季/年卡权益，锁客提升复购与用户价值。&lt;/p&gt;

&lt;p&gt;入驻/广告费：公会认证费、置顶费、广告位，被动收益。&lt;/p&gt;

&lt;p&gt;🔥 二、自动裂变体系，流量自增长&lt;/p&gt;

&lt;p&gt;多级分销：邀请返利 + 分佣，用户变推广员，零成本获客。&lt;/p&gt;

&lt;p&gt;公会管理：多公会入驻、层级抽成、自动结算，团队规模化变现。&lt;/p&gt;

&lt;p&gt;🔥 三、商业化功能，拉升留存转化&lt;/p&gt;

&lt;p&gt;智能派单：LBS+ 标签匹配，抢单/派单双模式，体验流畅。&lt;/p&gt;

&lt;p&gt;担保交易：独立钱包，订单完成自动结算，资金透明安全。&lt;/p&gt;

&lt;p&gt;三端互通：小程序 +H5+APP，全渠道引流沉淀私域。&lt;/p&gt;

&lt;p&gt;营销工具：新人礼、任务中心等，拉新促活一站式搞定。&lt;/p&gt;

&lt;p&gt;🔥 四、前端页面展示
&lt;img src="https://img.way2solo.com/photo/dkrjkf/b8ec1295-6131-4a27-a599-b4ec470c2e2e.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/55159f9f-aa8e-47ab-a978-5e791c522d07.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkrjkf/8d69dda0-b5bc-4d20-8bce-24ff5b9cc3f9.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;👤 谁适合用？
游戏公会会长 / 轻资产创业者 / 自媒体博主 / 线下电竞商家。&lt;/p&gt;

&lt;p&gt;💡 为什么选多客？
无需百万研发，一键部署。自带成熟盈利模型 + 落地运营指导，真正实现 0 技术、低成本搭建持续盈利平台。&lt;/p&gt;

&lt;p&gt;👉 立即获取系统 Demo 与专属落地方案！&lt;/p&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkrjkf/83a98457-0cbf-4ff3-a3a3-4edbc201fc07.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>dkrjkf</author>
      <pubDate>Wed, 15 Jul 2026 17:34:30 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7766</link>
      <guid>https://beta.w2solo.com/topics/7766</guid>
    </item>
    <item>
      <title>Novproxy 三类住宅代理极简选型指南</title>
      <description>&lt;p&gt;海外爬虫、跨境店铺运营、社媒自动化场景中，代理选错极易出现账号封禁、采集拦截、流量成本超支等问题。Novproxy 完整布局三类住宅代理，覆盖全部出海业务需求，下面为大家清晰区分。&lt;/p&gt;

&lt;p&gt;一、动态住宅代理&lt;/p&gt;

&lt;p&gt;资源来自全球真实家庭宽带，拥有 1.5 亿 + 纯净民用 IP 池，覆盖 195 个国家地区，支持国家、城市、邮编多级定位。提供轮换 IP、1–120 分钟粘性会话两种运行模式，采用阶梯流量计费，采购量级越大单价越低，大批量采购低至 0.5$/GB。&lt;/p&gt;

&lt;p&gt;适用场景：竞品价格采集、搜索引擎 SEO 监测、短期行业市场调研等轻量化数据抓取工作。&lt;/p&gt;

&lt;p&gt;二、静态 ISP 独享住宅代理&lt;/p&gt;

&lt;p&gt;海外正规运营商直供原生固定民用 IP，单人独享不限流量，订阅周期内 IP 地址恒定不变。严格执行一号一 IP，从网络底层规避多账号关联封禁，线路稳定，支持 7×24 小时不间断挂机。提供 7 天、30 天、90 天多周期套餐，批量采购最高可享 25% 折扣，单 IP 起步价 3.8 美元。&lt;/p&gt;

&lt;p&gt;适用场景：跨境电商多店铺矩阵、海外社媒长期运营账号、境外支付账户日常登录运维。&lt;/p&gt;

&lt;p&gt;三、无限流量包月代理&lt;/p&gt;

&lt;p&gt;采用固定月度资费，无流量消耗上限，支持数千线程高并发运行，分为带宽模式、端口模式两类方案。带宽模式随机分配全球 IP，适合持续大流量传输；端口模式可自主指定目标国家，自定义 3–30 分钟粘性会话。针对月消耗百 GB 至 TB 级流量的业务，相比动态流量计费方案可节省 50% 以上运营成本。&lt;/p&gt;

&lt;p&gt;适用场景：短视频、高清图片批量抓取、全天候广告投放核验、品牌侵权自动化巡检、长期 SEO 实时监控集群。&lt;/p&gt;

&lt;p&gt;Novproxy 通用核心优势&lt;/p&gt;

&lt;p&gt;1.协议全覆盖，兼容 HTTP、HTTPS、SOCKS5，后台可一键生成 API、账密配置，支持账号密码、IP 白名单双重安全校验；&lt;/p&gt;

&lt;p&gt;2.全球分布式节点部署，平均请求延迟低于 0.6 秒，官方保障 99.9% 线路可用率；&lt;/p&gt;

&lt;p&gt;3.三大产品线 IP 资源池完全隔离，采集业务网络不会污染账号运营 IP 的信誉；&lt;/p&gt;

&lt;p&gt;4.新手可购买小额套餐低成本测试线路，大型企业支持定制专属私有独立 IP 池。&lt;/p&gt;

&lt;p&gt;快速选型判断&lt;/p&gt;

&lt;p&gt;1.短期轻量化数据采集，无长期账号登录需求 → 动态住宅代理&lt;/p&gt;

&lt;p&gt;2.多店铺、多社媒账号矩阵，核心需求防关联、长期稳定网络环境 → 静态 ISP 独享 IP&lt;/p&gt;

&lt;p&gt;3.7×24 小时不间断自动化任务、月度流量消耗规模较大 → 无限流量包月套餐&lt;/p&gt;</description>
      <author>Novproxy6</author>
      <pubDate>Wed, 15 Jul 2026 17:22:28 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7765</link>
      <guid>https://beta.w2solo.com/topics/7765</guid>
    </item>
    <item>
      <title>工作室转型平台，只差一套源码的距离。陪玩陪聊系统私有化部署，数据 100% 归你</title>
      <description>&lt;p&gt;做陪玩陪聊生意的团队，大多都会经历一个共同的瓶颈期：订单多了，管理乱了；打手多了，算账难了；客户多了，留不住了。这时候你会发现，靠微信接单、靠 Excel 记账、靠人工派单的模式，天花板其实很低。&lt;/p&gt;

&lt;p&gt;为什么工作室需要一套自己的系统？
很多工作室起步时靠的是 “人力驱动”——客户发消息下单，客服在群里 @ 打手，打手接单后完成服务，再截图回来结算。这套流程在单量小的时候还能跑，一旦日单量超过几十单，问题就全冒出来了：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;漏单错单&lt;/strong&gt;：消息一多，谁接了谁的单根本理不清&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;结算扯皮&lt;/strong&gt;：对账全靠翻聊天记录，打手催款、客户退款，算不清楚&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;客户流失&lt;/strong&gt;：客户认的是你的微信号，哪天你换号或者不做了，客户就没了&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;打手管理难&lt;/strong&gt;：好打手不知道去哪儿接单，差打手你也不知道&lt;/p&gt;

&lt;p&gt;这些问题本质上不是 “不够努力” 造成的，而是工具跟不上业务规模。解决它们的办法，也不是招更多人，而是换一套系统。
&lt;img src="https://img.way2solo.com/photo/dkqqll/6f42df12-b863-4503-bad1-cd71e47bf3d0.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="源码交付 vs 租用SaaS：区别在哪里？"&gt;源码交付 vs 租用 SaaS：区别在哪里？&lt;/h2&gt;&lt;h3 id="市面上有两类解决方案，本质完全不同。"&gt;市面上有两类解决方案，本质完全不同。&lt;/h3&gt;
&lt;p&gt;租用 SaaS，简单来说就是 “开个账号用别人的系统”。数据和系统都跑在服务商的服务器上，你只有使用权。每单被抽成 10%-30%，功能是标准化的，想改个东西要排队等开发商排期，品牌也挂在别人名下。年费交了能用，不交就停。&lt;/p&gt;

&lt;p&gt;源码交付，独立部署，是一次性买断所有权。系统部署在你自己的服务器上，数据、用户、订单流水全都在你自己的数据库里。没有第三方抽成，想怎么改就怎么改，品牌是你自己的，用户沉淀在你自己的系统里。&lt;/p&gt;
&lt;h3 id="说白了：租用是在给平台打工，源码交付才是给自己建资产。"&gt;说白了：租用是在给平台打工，源码交付才是给自己建资产。&lt;/h3&gt;&lt;h3 id="两者的具体差异如下："&gt;两者的具体差异如下：&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkqqll/35a85180-0c9a-4b65-a237-68b8b4015781.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/dkqqll/f0f89c50-f4e9-43a0-9e9d-9d38e8e9eb2c.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="这套系统能帮你解决什么？"&gt;这套系统能帮你解决什么？&lt;/h2&gt;&lt;h3 id="一套成熟的陪玩陪聊系统，核心是把“人工驱动”变成“系统驱动”。"&gt;一套成熟的陪玩陪聊系统，核心是把 “人工驱动” 变成 “系统驱动”。&lt;/h3&gt;
&lt;p&gt;用户端（老板端）：选服务类型→选打手或发布需求→支付下单，三步完成。全程自助，不需要反复沟通确认。&lt;/p&gt;

&lt;p&gt;打手端：实时收到订单推送，自主抢单或接受派单。完成服务后上传截图申请结算，收益明细实时可查。个人主页展示战绩、接单记录、服务评分，帮打手积累口碑。&lt;/p&gt;

&lt;p&gt;客服端：与老板、打手实时沟通，派单分配，审核完成凭证，处理售后纠纷。所有订单状态一目了然。&lt;/p&gt;

&lt;p&gt;管理后台：所有订单、资金、用户数据在一个后台里跑通。价格、抽佣比例、活动规则全部自主配置。财务结算自动化，不用再手动对账。&lt;/p&gt;
&lt;h2 id="源码地址获取！！！前端全开源/api全开源系统地址"&gt;源码地址获取！！！前端全开源/api 全开源系统地址&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/dkqqll/48c65dfd-2b7d-403f-8b1d-3dc0e4ec695a.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>dkqqll</author>
      <pubDate>Wed, 15 Jul 2026 14:22:13 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7764</link>
      <guid>https://beta.w2solo.com/topics/7764</guid>
    </item>
    <item>
      <title>抓住 2026 校园服务数字化红利：基于 uni+php 的跑腿与社交小程序源码实战</title>
      <description>&lt;p&gt;想要在 2026 年抓住校园服务数字化的红利，核心就在于把 “跑腿” 和 “社交” 这两个高频场景深度绑定。跑腿业务能带来持续的现金流，而社交互动则是留住用户、形成平台壁垒的关键。
&lt;img src="https://img.way2solo.com/photo/DK11/8dbfef0e-c19e-4c91-a1e8-a0c3d784c960.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/DK11/1e045675-724e-4083-b243-6d86da2987f8.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
一、为什么现在是入场的好时机？
政策明确支持："十五五"规划将教育数字化列为重点，教育部明确推动 AI 赋能教育，鼓励各类"智慧校园"应用创新，校园创业环境比较友好。
市场需求已验证：高校学生普遍面临快递"最后一公里"配送难、信息分散在微信群、找兼职缺靠谱平台等痛点。像"蜂蜂校园"从代取快递起步，日均订单近两千单、年营收达百万元；"跑跑乐校园"上线不久就积累了超 4000 名用户，跑通了盈利模型。
技术与成本双友好：采用 Uni-app（前端跨端）+ PHP（后端）的方案，一套代码可生成小程序、APP、H5，开发成本比原生开发低很多，尤其适合初始资金有限的团队。
&lt;img src="https://img.way2solo.com/photo/DK11/ec22ef56-56ba-45aa-94c2-8c04e11efbe1.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/DK11/91c263fc-417c-46b0-903a-32ca28fa6e7e.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
二、Uni+PHP 校园系统的核心架构
这套系统通常分为三个端口，各司其职：
用户端（Uni-app）：学生通过微信小程序使用。核心功能包括一键下单（跑腿/代取快递/代买）、实时追踪（配送员在地图上的位置）、在线支付（集成微信支付）以及订单评价体系。针对社交模块，还包含动态发布、圈子互动、私信聊天等功能。
跑腿员/接单端（Uni-app）：类似骑手端 APP。核心功能包括实名认证、任务大厅（按距离/价格展示订单）、一键抢单及执行流程（从取件到送达全流程记录）。
管理后台（PHP）：整个系统的"大脑"。负责用户管理、订单调度与监控、跑腿员资质审核、数据统计分析，以及佣金比例设置和营销活动配置（如首单减免、邀请有礼）。
通过这套 “技术部署 + 跑腿落地 + 社交留存 + 数据优化” 的实战打法，你可以快速在校园市场建立起一个有壁垒的数字化服务平台。
&lt;img src="https://img.way2solo.com/photo/DK11/e523f627-8b83-468d-92fd-86885e3a2fbf.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;
&lt;img src="https://img.way2solo.com/photo/DK11/4cf581c6-e4c3-471f-a3a5-ee4b0d0b035d.png?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>DK11</author>
      <pubDate>Wed, 15 Jul 2026 14:02:11 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7763</link>
      <guid>https://beta.w2solo.com/topics/7763</guid>
    </item>
    <item>
      <title>给 Telegram 交了 3 次 smsfee 之后，我换了个客户端就上了</title>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tgclient.github.io/telegram-client/" rel="nofollow" target="_blank" title=""&gt;👉登录 telegram 问题典我即可自己解决👈&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/www_telegram_baby/3d157fe1-8967-4f1b-b892-a9cb676b964b.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;先说结论：smsfee 不是门槛，是陷阱。&lt;/p&gt;

&lt;p&gt;上周想上 Telegram 看技术频道，+86 手机号注册，验证码不来。提示 smsfee，交了，还是不来。再交，还不来。第三次的时候我停了——这玩意儿没尽头。&lt;/p&gt;

&lt;p&gt;网上教程全试过，换版本换运营商换网络清缓存，手机重装三遍，没用。&lt;/p&gt;

&lt;p&gt;后来朋友发了个客户端过来，基于官方 12.5.1 编译。我一开始没当回事，第三方客户端嘛，能用？&lt;/p&gt;

&lt;p&gt;下载，安装，打开，登录。没有验证码，没有 smsfee，直接进去了。&lt;/p&gt;

&lt;p&gt;全中文汉化，界面群组频道内容都是中文，时间格式数字显示本地化。打开自动连网，电信联通移动全稳。&lt;/p&gt;

&lt;p&gt;功能完整，聊天频道收消息多账号切换，和官方没差。推送及时，后台保活，一周没漏。&lt;/p&gt;

&lt;p&gt;基于官方源码编译，核心协议兼容。&lt;/p&gt;

&lt;p&gt;被 +86 验证码折磨过的人应该懂。链接放下面，自取。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tgclient.github.io/telegram-client/" rel="nofollow" target="_blank" title=""&gt;👉登录 telegram 问题典我即可自己解决👈&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src="https://img.way2solo.com/photo/www_telegram_baby/ac844345-951f-4493-a9ce-2f4b55c27fa8.jpg?imageView2/2/w/1920/q/100" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>www_telegram_baby</author>
      <pubDate>Wed, 15 Jul 2026 10:10:21 +0800</pubDate>
      <link>https://beta.w2solo.com/topics/7762</link>
      <guid>https://beta.w2solo.com/topics/7762</guid>
    </item>
  </channel>
</rss>
