<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Data Client Blog</title>
        <link>https://dataclient.io/zh-Hans/blog</link>
        <description>Data Client Blog</description>
        <lastBuildDate>Sat, 03 Oct 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[v0.19: Coding Agents, Batch Controller.set(), Faster TypeScript]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set</link>
            <guid>https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set</guid>
            <pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Set up Data Client with one prompt in Claude Code, Cursor or Codex, write many entities in one store update, and type-check endpoints about 2x faster]]></description>
            <content:encoded><![CDATA[
<p>v0.19 makes coding agents a first-class way to build with Data Client: one prompt sets up your app, and your agent
follows skills that ship with the packages you installed. It also lets a <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a> write a
whole batch of streamed rows in one store update, type-checks endpoint code about 2x faster, and fixes a round of
TypeScript and Vue issues.</p>
<p><strong>Coding Agents:</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agent-setup">One-prompt setup</a> - Add the <code>data-client</code> plugin to Claude Code, Cursor or Codex and ask it to set up Data Client; it installs the packages, adds the provider and links the skills your app needs</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#npm-skills">Skills ship in the packages</a> - <code>npx --no data-client-skills</code> links the skills your installed <code>@data-client/*</code> packages carry, so your agent follows the version you have instead of an older release</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agents-md">Agents keep using Data Client</a> - Setup adds a note to <code>AGENTS.md</code>, and each skill names the everyday tasks it covers, so later sessions reach for Data Client instead of <code>fetch</code> in <code>useEffect</code></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agent-debugging">Debug the running app</a> - In development, <code>globalThis.__DC__</code> gives your agent the store's <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller">Controller</a> and recent actions from Cursor's browser, Chrome DevTools MCP, Playwright MCP or Claude in Chrome</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-skills">Vue skills</a>, <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#llms-txt">llms.txt</a>, and skills <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#generated-references">generated from these docs</a></li>
</ul>
<p><strong>New APIs:</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#batch-set">Controller.set() with Array schemas</a> - Write many entities in one store update with <code>ctrl.set([Entity], rows)</code>, <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#batch-set-performance">up to 95x faster</a> than one <code>set()</code> per row</li>
</ul>
<p><strong>Performance:</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#faster-types">Faster TypeScript</a> - Editors and <code>tsc</code> check <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">RestEndpoint</a> and <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource">resource()</a> code <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#faster-types-results">about 2x faster with 40% less memory</a>, catching every error they caught before</li>
</ul>
<p><strong>Other Improvements:</strong></p>
<ul>
<li class="">Fix TypeScript 7 module resolution for package <code>exports</code>; imports now resolve to declaration files (<a href="https://github.com/reactive/data-client/pull/4019" target="_blank" rel="noopener noreferrer" class="">#4019</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> runs provider mount effects when the first render suspends (<a href="https://github.com/reactive/data-client/pull/4099" target="_blank" rel="noopener noreferrer" class="">#4099</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-set">Controller.set() values are typed by the schema</a>, so <code>ctrl.set(new schema.All(Todo), 42)</code> is a TypeScript error (<a href="https://github.com/reactive/data-client/pull/4133" target="_blank" rel="noopener noreferrer" class="">#4133</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#set-invalidate">Controller.set() deletes one entity with an Invalidate schema</a> without the one-row batch workaround (<a href="https://github.com/reactive/data-client/pull/4230" target="_blank" rel="noopener noreferrer" class="">#4230</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#extend-process-params">process() gets typed params</a> in <code>new RestEndpoint()</code>, <code>.extend()</code> and <code>resource().extend()</code>, so a wrong path parameter is a TypeScript error instead of <code>undefined</code> at runtime (<a href="https://github.com/reactive/data-client/pull/4183" target="_blank" rel="noopener noreferrer" class="">#4183</a>, <a href="https://github.com/reactive/data-client/pull/4184" target="_blank" rel="noopener noreferrer" class="">#4184</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-optimistic-response">getOptimisticResponse() returns are typed by the schema</a>, so a wrong field type is a TypeScript error instead of a flash of bad data (<a href="https://github.com/reactive/data-client/pull/4198" target="_blank" rel="noopener noreferrer" class="">#4198</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useLive">useLive()</a> keep the previous data while new arguments load, instead of returning <code>undefined</code> (<a href="https://github.com/reactive/data-client/pull/4131" target="_blank" rel="noopener noreferrer" class="">#4131</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useLive">useLive()</a> send fetch errors after arguments change to <code>onErrorCaptured()</code> instead of an unhandled promise rejection (<a href="https://github.com/reactive/data-client/pull/4135" target="_blank" rel="noopener noreferrer" class="">#4135</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a>, <a class="" href="https://dataclient.io/zh-Hans/vue/api/useDLE">useDLE()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useFetch">useFetch()</a> no longer refetch stale data on every store update, so a <code>controller.set()</code> is not overwritten (<a href="https://github.com/reactive/data-client/pull/4134" target="_blank" rel="noopener noreferrer" class="">#4134</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-stale-while-revalidate">shows stale data on mount</a> and refetches in the background, like React, instead of showing the <code>&lt;Suspense&gt;</code> fallback until the refetch finishes (<a href="https://github.com/reactive/data-client/pull/4169" target="_blank" rel="noopener noreferrer" class="">#4169</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useDLE">useDLE()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useCache">useCache()</a> keep expired <code>invalidIfStale</code> data through unrelated store updates instead of getting stuck loading (<a href="https://github.com/reactive/data-client/pull/4142" target="_blank" rel="noopener noreferrer" class="">#4142</a>)</li>
<li class="">Vue <code>DataClientPlugin</code> installs on Vue versions before 3.5 instead of throwing <code>app.onUnmount is not a function</code> (<a href="https://github.com/reactive/data-client/pull/4146" target="_blank" rel="noopener noreferrer" class="">#4146</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin#gcPolicy">DataClientPlugin</a> garbage collects by default, matching React's <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a>, so you no longer need to pass <code>gcPolicy</code>; <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-gc">how it decides what to remove</a> (<a href="https://github.com/reactive/data-client/pull/4148" target="_blank" rel="noopener noreferrer" class="">#4148</a>)</li>
<li class="">Vue composables accept <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-getter-args">getter arguments</a> like <code>() =&gt; ({ id: props.id })</code>; they were typed to allow them but passed the function itself to the endpoint (<a href="https://github.com/reactive/data-client/pull/4115" target="_blank" rel="noopener noreferrer" class="">#4115</a>)</li>
<li class="">Fix <code>Cannot find name 'NoInfer'</code> and <code>export type</code> errors on TypeScript 4.x with <code>skipLibCheck</code> off (<a href="https://github.com/reactive/data-client/pull/4138" target="_blank" rel="noopener noreferrer" class="">#4138</a>)</li>
<li class="">Fix <code>Entity</code>, <code>Endpoint</code>, <code>Union</code> and <code>RestEndpoint</code> type errors on TypeScript 4.0–4.5 with <code>skipLibCheck</code> off (<a href="https://github.com/reactive/data-client/pull/4140" target="_blank" rel="noopener noreferrer" class="">#4140</a>)</li>
<li class="">Fix <code>',' expected</code> errors importing <code>@data-client/react/redux</code>, <code>@data-client/react/nextjs</code> or <code>@data-client/test</code> on TypeScript 4.0–4.4 (<a href="https://github.com/reactive/data-client/pull/4232" target="_blank" rel="noopener noreferrer" class="">#4232</a>)</li>
<li class="">Fix <code>act</code> and <code>renderHook</code> from <code>@data-client/test</code> typed as <code>any</code> on TypeScript 4.0–4.4 (<a href="https://github.com/reactive/data-client/pull/4251" target="_blank" rel="noopener noreferrer" class="">#4251</a>)</li>
<li class="">React Native <a class="" href="https://dataclient.io/zh-Hans/docs/api/useSuspense">useSuspense()</a>, <a class="" href="https://dataclient.io/zh-Hans/docs/api/useFetch">useFetch()</a> and <a class="" href="https://dataclient.io/zh-Hans/docs/api/useDLE">useDLE()</a> refetch on screen focus only when the current data is stale or invalid, instead of refetching fresh data on every refocus (<a href="https://github.com/reactive/data-client/pull/4378" target="_blank" rel="noopener noreferrer" class="">#4378</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> works with React Native Testing Library 14 and stays synchronous, so <code>renderDataHook()</code> calls need no <code>await</code> (<a href="https://github.com/reactive/data-client/pull/4374" target="_blank" rel="noopener noreferrer" class="">#4374</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a> classes can be used where an <code>EntityInterface</code> is expected (<a href="https://github.com/reactive/data-client/pull/4149" target="_blank" rel="noopener noreferrer" class="">#4149</a>); <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#entity-pk-args">prepare <code>pk()</code> overrides</a> for a future release</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/useCache">useCache()</a> and <a class="" href="https://dataclient.io/zh-Hans/docs/api/useDLE">useDLE()</a> return <code>undefined</code> for a deleted entity whose refetch failed, instead of a truthy <code>Symbol</code> that slipped past <code>if (!data)</code> checks; <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#deleted-entity-undefined">remove any workarounds</a> (<a href="https://github.com/reactive/data-client/pull/4150" target="_blank" rel="noopener noreferrer" class="">#4150</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useFetch">useFetch()</a> keeps its data from being garbage collected while mounted, like <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a>, so a configured <code>gcPolicy</code> no longer evicts prefetched data that components read later (<a href="https://github.com/reactive/data-client/pull/4152" target="_blank" rel="noopener noreferrer" class="">#4152</a>)</li>
<li class="">Apps with <a class="" href="https://dataclient.io/zh-Hans/docs/getting-started/debugging">Redux DevTools</a> open no longer stutter in development on large stores or frequent updates; each update <a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#devtools-perf">serializes 40-60x faster</a> (<a href="https://github.com/reactive/data-client/pull/4163" target="_blank" rel="noopener noreferrer" class="">#4163</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#extend">resource().extend()</a> with an object of endpoint overrides keeps endpoints added earlier with <code>.extend('name', options)</code> in its type, so using them is no longer a TypeScript error (<a href="https://github.com/reactive/data-client/pull/4184" target="_blank" rel="noopener noreferrer" class="">#4184</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#query-collection-push">RestEndpoint.push</a>, <code>unshift</code> and <code>remove</code> accept the Entity's fields as the body when a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> or <a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy">Lazy</a> wraps the <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>, instead of only <code>FormData</code> (<a href="https://github.com/reactive/data-client/pull/4226" target="_blank" rel="noopener noreferrer" class="">#4226</a>)</li>
<li class="">Vue <a class="" href="https://dataclient.io/zh-Hans/vue/api/useFetch">useFetch()</a> is typed as the read-only <code>Ref</code> it returns, so <code>promise.resolved</code> (always <code>undefined</code>) is now a TypeScript error; read <code>promise.value.resolved</code> instead (<a href="https://github.com/reactive/data-client/pull/4114" target="_blank" rel="noopener noreferrer" class="">#4114</a>)</li>
<li class="">A <code>Controller</code> subclass passed to <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider#Controller">DataProvider</a> or <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin#Controller">DataClientPlugin</a> no longer needs a cast to type-check (<a href="https://github.com/reactive/data-client/pull/4228" target="_blank" rel="noopener noreferrer" class="">#4228</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/guides/redux">prepareStore()</a>'s <code>store</code> can be passed to react-redux's <code>&lt;Provider&gt;</code> without a cast, and has <code>dispatch()</code> in its type (<a href="https://github.com/reactive/data-client/pull/4238" target="_blank" rel="noopener noreferrer" class="">#4238</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#create-formdata">resource().create accepts FormData</a> without a cast, like <code>update</code>, <code>partialUpdate</code> and <code>getList.push</code> (<a href="https://github.com/reactive/data-client/pull/4235" target="_blank" rel="noopener noreferrer" class="">#4235</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#push">RestEndpoint.push</a>, <code>unshift</code> and <code>remove</code> send an array body as JSON, so creating or removing several items at once no longer sends <code>"[object Object]"</code> to your server; <code>resource().create</code> takes an array too (<a href="https://github.com/reactive/data-client/pull/4262" target="_blank" rel="noopener noreferrer" class="">#4262</a>)</li>
<li class="">Polling keeps the schema of endpoints given <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#pollfrequency">pollFrequency</a> with <code>.extend()</code>, so a polled <a class="" href="https://dataclient.io/zh-Hans/docs/api/useLive">useLive()</a> list updates right away from mutations and optimistic updates instead of waiting for the next poll (<a href="https://github.com/reactive/data-client/pull/4437" target="_blank" rel="noopener noreferrer" class="">#4437</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a> only warns that it doesn't update during SSR when something fetches while the server renders, instead of on every server render, so pages that load data after mount (like Expo Router's static web output) stay quiet (<a href="https://github.com/reactive/data-client/pull/4449" target="_blank" rel="noopener noreferrer" class="">#4449</a>)</li>
<li class="">Server rendering with React 19 no longer logs "Uncaught suspense" when nothing suspended; React renders and discards fallbacks of large boundaries, and the warning now waits for a fallback that actually shows (<a href="https://github.com/reactive/data-client/pull/4450" target="_blank" rel="noopener noreferrer" class="">#4450</a>)</li>
<li class="">Vue <code>createDataClient()</code> is deprecated, since it's internal to <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin">DataClientPlugin</a>; install the plugin with <code>app.use(DataClientPlugin, options)</code> instead of calling it directly (<a href="https://github.com/reactive/data-client/pull/4193" target="_blank" rel="noopener noreferrer" class="">#4193</a>)</li>
<li class="">Vue <code>renderDataCompose()</code>'s <code>waitForNextUpdate()</code> is deprecated, since it gives up silently after 1 second and lets a test pass while still suspended; <code>await result</code> instead, or <code>await allSettled()</code> after a change, which now also waits for fetches a prop change starts (<a class="" href="https://dataclient.io/zh-Hans/vue/guides/unit-testing-composables#renderdatacompose-api">unit testing composables</a>, <a href="https://github.com/reactive/data-client/pull/4221" target="_blank" rel="noopener noreferrer" class="">#4221</a>)</li>
</ul>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#migration-guide">Breaking Changes:</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typescript-4">TypeScript 4.0 or later is required</a> - the TypeScript 3.x declarations are removed (<a href="https://github.com/reactive/data-client/pull/4151" target="_blank" rel="noopener noreferrer" class="">#4151</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#manager-middleware">Managers must define <code>middleware</code></a> - <code>getMiddleware()</code> is removed (<a href="https://github.com/reactive/data-client/pull/4378" target="_blank" rel="noopener noreferrer" class="">#4378</a>, <a href="https://github.com/reactive/data-client/pull/4382" target="_blank" rel="noopener noreferrer" class="">#4382</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#test-react-0.15">@data-client/test requires @data-client/react 0.15.3 or later</a> (<a href="https://github.com/reactive/data-client/pull/4414" target="_blank" rel="noopener noreferrer" class="">#4414</a>)</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#dc-global"><code>globalThis.__DC__</code> replaces <code>__DC_CONTROLLERS__</code></a> in development (<a href="https://github.com/reactive/data-client/pull/4435" target="_blank" rel="noopener noreferrer" class="">#4435</a>)</li>
</ul>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-releases">Get ready for future releases:</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-pk-args">Type <code>args</code> as <code>readonly</code> in <code>Entity.pk()</code> overrides</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-create-data-client">Use <code>DataClientPlugin</code> instead of Vue <code>createDataClient()</code></a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-wait-for-next-update">Replace <code>waitForNextUpdate()</code> in Vue tests</a></li>
</ul>
<!-- -->
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="agents">Coding agents<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agents" class="hash-link" aria-label="Coding agents的直接链接" title="Coding agents的直接链接" translate="no">​</a></h2>
<p>Coding agents write a lot of Data Client code, and they write it well when they have the current APIs instead of
guessing from older releases they were trained on. v0.19 gets your agent those APIs in one step, keeps them matched
to the version you install, and lets it check the running app.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="agent-setup">Set up with one prompt<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agent-setup" class="hash-link" aria-label="Set up with one prompt的直接链接" title="Set up with one prompt的直接链接" translate="no">​</a></h3>
<p>Add the <code>data-client</code> plugin to your agent, then ask it to set up Data Client:</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs tabs_mHRD"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV claude_R4UC tabs__item--active">Claude Code</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV cursor_zvAy">Cursor</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV codex_cvY9">Codex</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV other_M39Q">Other agents</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l"><span class="terminalTitle_sx3z"><svg class="terminalIcon_jv7e" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19h8"></path><path d="m4 17 6-6-6-6"></path></svg>终端</span></div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">claude plugin marketplace </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--scope</span><span class="token plain"> project </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--sparse</span><span class="token plain"> .claude-plugin .agents/skills</span><br></div><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">claude plugin </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> data-client@data-client </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--scope</span><span class="token plain"> project</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div><div class="agentPrompt__MJg framed_jzqs"><button type="button" class="clean-btn prompt_J3Oq" aria-describedby="_R_hgjqllq9_"><svg class="spark_sePl" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"></path><path d="M20 3v4"></path><path d="M22 5h-4"></path><path d="M4 17v2"></path><path d="M5 18H3"></path></svg><span class="label_iEid">Claude Code 智能体对话</span><span class="text_e86Q">/data-client:data-client-setup Set up <span class="pkg_Mw_1">@data-client/react</span> and use it for all API data</span><span class="copyIcons_gf7Z" aria-hidden="true"><svg class="copyIcon_GHJa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><svg class="checkIcon_mm76" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg></span></button><span role="tooltip" id="_R_hgjqllq9_" class="tip_NYx7 tip_cCYE" aria-live="polite">复制给 Claude Code 的提示词</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="agentPrompt__MJg framed_jzqs"><button type="button" class="clean-btn prompt_J3Oq" aria-describedby="_R_agjqllq9_"><svg class="spark_sePl" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"></path><path d="M20 3v4"></path><path d="M22 5h-4"></path><path d="M4 17v2"></path><path d="M5 18H3"></path></svg><span class="label_iEid">Cursor 智能体对话</span><span class="text_e86Q">/add-plugin data-client@https://github.com/reactive/data-client</span><span class="copyIcons_gf7Z" aria-hidden="true"><svg class="copyIcon_GHJa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><svg class="checkIcon_mm76" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg></span></button><span role="tooltip" id="_R_agjqllq9_" class="tip_NYx7 tip_cCYE" aria-live="polite">复制给 Cursor 的提示词</span></div><p>Then, in a new chat:</p><div class="agentPrompt__MJg framed_jzqs"><button type="button" class="clean-btn prompt_J3Oq" aria-describedby="_R_qgjqllq9_"><svg class="spark_sePl" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"></path><path d="M20 3v4"></path><path d="M22 5h-4"></path><path d="M4 17v2"></path><path d="M5 18H3"></path></svg><span class="label_iEid">Cursor 智能体对话</span><span class="text_e86Q">/data-client-setup Set up <span class="pkg_Mw_1">@data-client/react</span> and use it for all API data</span><span class="copyIcons_gf7Z" aria-hidden="true"><svg class="copyIcon_GHJa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><svg class="checkIcon_mm76" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg></span></button><span role="tooltip" id="_R_qgjqllq9_" class="tip_NYx7 tip_cCYE" aria-live="polite">复制给 Cursor 的提示词</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l"><span class="terminalTitle_sx3z"><svg class="terminalIcon_jv7e" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19h8"></path><path d="m4 17 6-6-6-6"></path></svg>终端</span></div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">codex plugin marketplace </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--sparse</span><span class="token plain"> .claude-plugin </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--sparse</span><span class="token plain"> .agents/skills</span><br></div><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">codex plugin </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> data-client@data-client</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div><div class="agentPrompt__MJg framed_jzqs"><button type="button" class="clean-btn prompt_J3Oq" aria-describedby="_R_jgjqllq9_"><svg class="spark_sePl" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"></path><path d="M20 3v4"></path><path d="M22 5h-4"></path><path d="M4 17v2"></path><path d="M5 18H3"></path></svg><span class="label_iEid">Codex 智能体对话</span><span class="text_e86Q">$data-client:data-client-setup Set up <span class="pkg_Mw_1">@data-client/react</span> and use it for all API data</span><span class="copyIcons_gf7Z" aria-hidden="true"><svg class="copyIcon_GHJa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><svg class="checkIcon_mm76" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg></span></button><span role="tooltip" id="_R_jgjqllq9_" class="tip_NYx7 tip_cCYE" aria-live="polite">复制给 Codex 的提示词</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="agentPrompt__MJg framed_jzqs"><button type="button" class="clean-btn prompt_J3Oq" aria-describedby="_R_4gjqllq9_"><svg class="spark_sePl" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"></path><path d="M20 3v4"></path><path d="M22 5h-4"></path><path d="M4 17v2"></path><path d="M5 18H3"></path></svg><span class="label_iEid">智能体对话</span><span class="text_e86Q">所有服务器状态都使用 <span class="pkg_Mw_1">@data-client/react</span></span><span class="copyIcons_gf7Z" aria-hidden="true"><svg class="copyIcon_GHJa" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg><svg class="checkIcon_mm76" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"></path></svg></span></button><span role="tooltip" id="_R_4gjqllq9_" class="tip_NYx7 tip_cCYE" aria-live="polite">复制给编程代理的提示词</span></div></div></div></div>
<p>The setup skill detects React or Vue and your API style (REST, GraphQL or custom async functions), installs the
packages, adds the provider, and links the skills those packages ship. For REST it also moves your existing <code>fetch</code> or
axios calls to <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">endpoints</a> (<a href="https://github.com/reactive/data-client/pull/4153" target="_blank" rel="noopener noreferrer" class="">#4153</a>).
Claude Code installs the plugin for the project, so teammates who open it get the plugin too. The package READMEs
on npm open with the same setup (<a href="https://github.com/reactive/data-client/pull/4454" target="_blank" rel="noopener noreferrer" class="">#4454</a>).</p>
<p>The plugin only sets apps up, so it carries just the setup skill and the <code>data-client</code> skill
<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agents-md" class="">below</a>. Every other skill comes from your packages, below. Agents without a plugin take the <strong>Other agents</strong>
prompt, which installs the setup skill with the <a href="https://skills.sh/" target="_blank" rel="noopener noreferrer" class="">skills CLI</a> first.
<a href="https://github.com/reactive/data-client/pull/4410" target="_blank" rel="noopener noreferrer" class="">#4410</a>,
<a href="https://github.com/reactive/data-client/pull/4425" target="_blank" rel="noopener noreferrer" class="">#4425</a>,
<a href="https://github.com/reactive/data-client/pull/4427" target="_blank" rel="noopener noreferrer" class="">#4427</a>,
<a href="https://github.com/reactive/data-client/pull/4439" target="_blank" rel="noopener noreferrer" class="">#4439</a>,
<a href="https://github.com/reactive/data-client/pull/4440" target="_blank" rel="noopener noreferrer" class="">#4440</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="npm-skills">Skills ship in the packages<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#npm-skills" class="hash-link" aria-label="Skills ship in the packages的直接链接" title="Skills ship in the packages的直接链接" translate="no">​</a></h3>
<p>Each <code>@data-client/*</code> package now carries the skills for its own APIs, so your agent follows the version you have
installed and gets new guidance with each upgrade. <code>data-client-skills</code> (in <code>@data-client/react</code>, <code>vue</code>, <code>rest</code>,
<code>graphql</code> and <code>endpoint</code>) links them into <code>.agents/skills</code>, with <code>.claude/skills</code> linking to it, where Claude Code,
Cursor and Codex load them as their own skills.</p>
<figure class="figure_HN5N"><figcaption class="caption_pMal">Skills used to be copied from GitHub master; now they come from the packages you installed.</figcaption><div class="grid_iD3H wrap_ES0G"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l"><span class="terminalTitle_sx3z"><svg class="terminalIcon_jv7e" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19h8"></path><path d="m4 17 6-6-6-6"></path></svg>Before</span></div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx skills </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token punctuation" style="color:rgb(199, 146, 234)">\</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> data-client-react </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> data-client-rest </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> data-client-schema</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l"><span class="terminalTitle_sx3z"><svg class="terminalIcon_jv7e" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19h8"></path><path d="m4 17 6-6-6-6"></path></svg>After</span></div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--no</span><span class="token plain"> data-client-skills</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div></figure>
<p>Commit the links, and run the command again after adding, removing or upgrading <code>@data-client</code> packages
(<a class="" href="https://dataclient.io/zh-Hans/docs/getting-started/agent-skills">Agent Skills</a> has the details). If you installed skills with <code>npx skills add</code>
before, remove those copies first (<code>npx skills remove data-client-react -y</code>); the command keeps folders it didn't
create and says so.
<a href="https://github.com/reactive/data-client/pull/4407" target="_blank" rel="noopener noreferrer" class="">#4407</a>,
<a href="https://github.com/reactive/data-client/pull/4410" target="_blank" rel="noopener noreferrer" class="">#4410</a></p>
<p>Upgrade skills ship in the packages too. <code>data-client-v0.18-migration</code> runs the <a href="https://dataclient.io/zh-Hans/assets/files/v0.18-57a9e93e47ddbc37fc4ab436a1aa882b.js" target="_blank" class="">codemod</a>, then
handles what it can't (<a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#migration-guide">v0.18 migration</a>), and
<code>path-to-regexp-v8-migration</code> rewrites
<a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#path-to-regexp-v8">path syntax</a> in your endpoints.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="agents-md">Agents keep using Data Client<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agents-md" class="hash-link" aria-label="Agents keep using Data Client的直接链接" title="Agents keep using Data Client的直接链接" translate="no">​</a></h3>
<p>An agent in a later session doesn't know the setup happened, so it can fall back to <code>fetch</code> in <code>useEffect</code> or
app-wide context. Setup now adds a note to your project's <code>AGENTS.md</code>, which Cursor, Codex and Claude Code read at the
start of every session (setup adds <code>@AGENTS.md</code> to your <code>CLAUDE.md</code> if you have one):</p>
<div class="language-md codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">AGENTS.md</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-md codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">This app manages server state (fetching, caching, mutations and real-time updates) with Reactive Data Client. Use it</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">for all server data, and read the matching </span><span class="token code-snippet code keyword" style="font-style:italic">`data-client-*`</span><span class="token plain"> skill before writing, changing or debugging code that loads</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">or changes data. After adding, removing or upgrading </span><span class="token code-snippet code keyword" style="font-style:italic">`@data-client/*`</span><span class="token plain"> packages, run </span><span class="token code-snippet code keyword" style="font-style:italic">`npx --no data-client-skills`</span><span class="token plain"> and</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">commit the skill links.</span><br></div></code></pre></div></div>
<p>Each skill's description now names the work it covers in everyday terms, like loading and error states, forms, or data
that looks stale on screen, instead of listing hook names, so agents load it for those tasks even when you never
mention Data Client. Adding or changing an endpoint that returns data loads <code>data-client-schema</code>, so the endpoint's responses
are normalized into the shared cache with <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entities</a>. The <code>data-client</code> skill starts any Data Client task and points your
agent at the skill for it.
<a href="https://github.com/reactive/data-client/pull/4408" target="_blank" rel="noopener noreferrer" class="">#4408</a>,
<a href="https://github.com/reactive/data-client/pull/4428" target="_blank" rel="noopener noreferrer" class="">#4428</a>,
<a href="https://github.com/reactive/data-client/pull/4453" target="_blank" rel="noopener noreferrer" class="">#4453</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="agent-debugging">Debug the running app<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#agent-debugging" class="hash-link" aria-label="Debug the running app的直接链接" title="Debug the running app的直接链接" translate="no">​</a></h3>
<p>Ask your agent "why didn't this refetch?" or "what's in the cache right now?" and it can check the running app instead
of guessing from code. In development, <a class="" href="https://dataclient.io/zh-Hans/docs/api/DevToolsManager#controllers">DevToolsManager</a> puts the store on
<code>globalThis.__DC__</code>: <code>__DC__.controller</code> is its <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller">Controller</a>, and <code>__DC__.actions</code> its recent
actions, recorded from the moment the app starts, with or without the Redux DevTools extension. Production builds
don't include it.</p>
<div class="language-js codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Browser DevTools console</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-js codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">__DC__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">__DC__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">actions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">slice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>The React and Vue skills read it from any browser tool that runs JavaScript in the page: Cursor's built-in browser,
<a href="https://github.com/ChromeDevTools/chrome-devtools-mcp" target="_blank" rel="noopener noreferrer" class="">Chrome DevTools MCP</a>,
<a href="https://github.com/microsoft/playwright-mcp" target="_blank" rel="noopener noreferrer" class="">Playwright MCP</a> or Claude in Chrome, and match dispatched actions to network requests; see
<a class="" href="https://dataclient.io/zh-Hans/docs/getting-started/debugging#debugging-with-agents">debugging with agents</a>. If your own
scripts read <code>__DC_CONTROLLERS__</code>, <a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#dc-global" class="">switch them to <code>__DC__</code></a>.
<a href="https://github.com/reactive/data-client/pull/4435" target="_blank" rel="noopener noreferrer" class="">#4435</a>,
<a href="https://github.com/reactive/data-client/pull/4428" target="_blank" rel="noopener noreferrer" class="">#4428</a>,
<a href="https://github.com/reactive/data-client/pull/4447" target="_blank" rel="noopener noreferrer" class="">#4447</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="vue-skills">Vue skills<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-skills" class="hash-link" aria-label="Vue skills的直接链接" title="Vue skills的直接链接" translate="no">​</a></h3>
<p>Vue projects used to get the React hooks skill, so agents reached for React patterns. The <code>data-client-vue</code> skill
writes <code>DataClientPlugin</code> and composable code and <a class="" href="https://dataclient.io/zh-Hans/vue/getting-started/debugging#debugging-with-agents">debugs a running app</a>,
and <code>data-client-vue-testing</code> writes <code>renderDataCompose()</code> and <code>mountDataClient()</code> tests that follow the
<a class="" href="https://dataclient.io/zh-Hans/vue/guides/unit-testing-composables">Vue testing guides</a>.
<a href="https://github.com/reactive/data-client/pull/4126" target="_blank" rel="noopener noreferrer" class="">#4126</a>,
<a href="https://github.com/reactive/data-client/pull/4181" target="_blank" rel="noopener noreferrer" class="">#4181</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="llms-txt">llms.txt<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#llms-txt" class="hash-link" aria-label="llms.txt的直接链接" title="llms.txt的直接链接" translate="no">​</a></h3>
<p>Agents without skills can read the docs as markdown, following the <a href="https://llmstxt.org/" target="_blank" rel="noopener noreferrer" class="">llms.txt</a> convention:</p>
<ul>
<li class=""><a href="https://dataclient.io/llms.txt" target="_blank" rel="noopener noreferrer" class="">llms.txt</a> for React and <a href="https://dataclient.io/vue/llms.txt" target="_blank" rel="noopener noreferrer" class="">vue/llms.txt</a> for Vue index every page, and <code>llms-full.txt</code> beside each holds them all in one file</li>
<li class=""><a href="https://dataclient.io/rest/llms.txt" target="_blank" rel="noopener noreferrer" class="">rest/llms.txt</a> and <a href="https://dataclient.io/graphql/llms.txt" target="_blank" rel="noopener noreferrer" class="">graphql/llms.txt</a> cover just that package's API</li>
<li class="">Any docs page is markdown when you add <code>.md</code> to its URL, like <a href="https://dataclient.io/docs/api/useSuspense.md" target="_blank" rel="noopener noreferrer" class="">/docs/api/useSuspense.md</a></li>
</ul>
<p>Every page links its llms.txt in <code>&lt;head&gt;</code>, and every docs page links its markdown, so an agent given any page URL
finds them on its own. The setup pages' markdown gives agents the setup steps directly.
<a href="https://github.com/reactive/data-client/pull/4171" target="_blank" rel="noopener noreferrer" class="">#4171</a>,
<a href="https://github.com/reactive/data-client/pull/4236" target="_blank" rel="noopener noreferrer" class="">#4236</a>,
<a href="https://github.com/reactive/data-client/pull/4427" target="_blank" rel="noopener noreferrer" class="">#4427</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="generated-references">Skills match the docs<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#generated-references" class="hash-link" aria-label="Skills match the docs的直接链接" title="Skills match the docs的直接链接" translate="no">​</a></h3>
<p>Skill reference pages are generated per framework from these docs, so they carry shared snippets like install commands
and give Vue projects only Vue code. A CI check fails when a skill drifts from the docs, so skills stay current with
each release. <a href="https://github.com/reactive/data-client/pull/4170" target="_blank" rel="noopener noreferrer" class="">#4170</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="batch-set">Batch Controller.set()<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#batch-set" class="hash-link" aria-label="Batch Controller.set()的直接链接" title="Batch Controller.set()的直接链接" translate="no">​</a></h2>
<p>A <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a> that receives a stream of rows (like price tickers over a websocket) can now write
them all with one <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set-array">Controller.set()</a> by passing an <a class="" href="https://dataclient.io/zh-Hans/rest/api/Array">Array</a> schema.
Before v0.19, <code>[Ticker]</code> was a TypeScript error, so the usual workaround was a <code>set()</code> per row:</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ws</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function-variable function" style="color:rgb(130, 170, 255)">onmessage</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> event </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> rows </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">event</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> row </span><span class="token keyword" style="font-style:italic">of</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> product_id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">product_id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> row</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ws</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function-variable function" style="color:rgb(130, 170, 255)">onmessage</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> event </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> rows </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">event</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>Each row merges with its stored entity, and entities not in the list are untouched. Array schemas take no <code>args</code> and
no updater function. To batch mixed Entity types, deletes, or rows keyed by id, pass a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a>,
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Invalidate#batch-invalidation">Invalidate</a>, or <a class="" href="https://dataclient.io/zh-Hans/rest/api/Values">Values</a> schema; see
<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set-array">Controller.set()</a> for examples.
<a href="https://github.com/reactive/data-client/pull/4103" target="_blank" rel="noopener noreferrer" class="">#4103</a></p>
<p>Try both buttons below. This browser check starts from an empty store and times <code>Promise.all</code> of 500 <code>set()</code>
calls against one batch <code>set()</code>. Both paths are one React commit, and each writes 500 new prices.</p>
<div data-playground="true" class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA row_YGZs"><div class="playgroundTextEdit_rt2K withCover_yq1Z"><div class="editorBody_JtfR"><div class="editorDocs_INVk"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">Ticker</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">PriceStream</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-tsx" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useController</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> useQuery </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">Ticker</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> newPrices </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./Ticker'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">PriceStream</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">timing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> setTiming</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">useState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> first </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> product_id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'COIN-0'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">time</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    label</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">write</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">rows</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">ReturnType</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token keyword" style="font-style:italic">typeof</span><span class="token plain"> newPrices</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Promise</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">unknown</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> rows </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">newPrices</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> start </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token dom variable" style="color:rgb(191, 199, 213)">performance</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">now</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">write</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">rows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">setTiming</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">label</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">performance</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">now</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation operator" style="color:rgb(137, 221, 255)">-</span><span class="token template-string interpolation"> start</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">toFixed</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation number" style="color:rgb(247, 140, 108)">1</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> ms</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">perRow</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'500 set() calls'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> rows </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Promise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">all</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        rows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">row </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> product_id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> row</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">product_id</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> row</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// highlight-next-line</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">batch</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'1 batch set()'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> rows </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token maybe-class-name">Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> rows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">perRow</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">set() per row</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string" style="color:rgb(195, 232, 141)">' '</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">batch</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">batch set()</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">COIN-0: </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">first </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">$</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">first</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">price</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'no data yet'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">timing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">PriceStream</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div><div class="storeHost_N0SU"></div><button type="button" class="clean-btn swap_P7aB storeBadge_yrOO" title="显示 Store" aria-pressed="false" data-store-toggle="true"><span aria-hidden="false"><span class="storeBadgeDot_pVWi"></span>Store</span><span aria-hidden="true"><svg class="storeBadgeCode_DfYa" viewBox="0 0 24 24" width="1.15em" height="1.15em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 7-5 5 5 5M16 7l5 5-5 5M14 4l-4 16"></path></svg>代码</span></button></div></div><div class="previewWrapper_edd2"><div class="playgroundHeader_Zx4K previewHeader_MW_M"><span class="liveLabel_MHnJ"><span class="liveLabelText_k6qc">实时预览</span></span><span class="routerSlot_CTii"></span><span class="previewControls_oxCt"><button type="button" class="clean-btn headerButton_h2KM storeHeaderToggle_ToEw" title="显示 Store" aria-label="Store" aria-pressed="false" data-store-toggle="true" disabled=""><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"></ellipse><path d="M4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5"></path><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"></path></svg></button></span></div><div class="playgroundResult_tefG"><div class="playgroundPreview_rk9R"></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="batch-set-performance">Performance<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#batch-set-performance" class="hash-link" aria-label="Performance的直接链接" title="Performance的直接链接" translate="no">​</a></h3>
<p>Each <code>set()</code> is a separate store update, and every store update copies that entity type's table. Writing rows one
at a time repeats that copy for every row, so the cost grows with both the batch size and the store size. A batch
pays that copy once.</p>
<p>The chart is the node <code>setMany</code> benchmark in
<a href="https://github.com/reactive/data-client/blob/master/examples/benchmark/core.js" target="_blank" rel="noopener noreferrer" class="">examples/benchmark/core.js</a>:
a store that already holds 500 entities, then a synchronous <code>set()</code> per row against one <code>set([Ticker], rows)</code>.
It measures the store update: <strong>20x</strong> faster for 50 rows and <strong>95x</strong> faster for 500 rows.
<a href="https://github.com/reactive/data-client/pull/4103" target="_blank" rel="noopener noreferrer" class="">#4103</a></p>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">Node setMany into a 500-entity store</figcaption><div class="bars_HVEW" style="--perf-one:1.0485436893203883%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">50 rows</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:20.97087378640777%;--perf-split:5%"></span></span><span class="text--bold">20x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">One set() per row<!-- --> <!-- -->10.8<!-- --> <!-- -->ms<!-- --> → <!-- -->set([Ticker], rows)<!-- --> <strong>0.54<!-- --> <!-- -->ms</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">500 rows</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:100%;--perf-split:1.0485436893203883%"></span></span><span class="text--bold">95x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">One set() per row<!-- --> <!-- -->103<!-- --> <!-- -->ms<!-- --> → <!-- -->set([Ticker], rows)<!-- --> <strong>1.08<!-- --> <!-- -->ms</strong></span></span></div></div></figure>
<center><p><a href="https://reactive.github.io/data-client/dev/bench/" target="_blank" rel="noopener noreferrer" class="">Benchmarks over time</a> | <a href="https://github.com/reactive/data-client/blob/master/examples/benchmark/core.js" target="_blank" rel="noopener noreferrer" class="">View setMany benchmark</a></p></center>
<p>In a <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a>, buffer incoming messages and flush each batch with one <code>set()</code>, as described in
<a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers#batching">Batching high-frequency updates</a>. The coin app's <code>StreamManager</code> now
flushes Coinbase ticker messages this way.</p>
<center><video width="600" controls="" muted="" playsinline="" loop="" aria-label="Redux DevTools for two copies of the coin app's StreamManager receiving three bursts of 500 ticker messages. Calling set() for each message logs 1,500 set actions, while buffering messages and flushing them with set([Ticker], rows) logs 3." style="width:100%"><source src="/zh-Hans/videos/blog/batch-set-devtools.webm" type="video/webm">Redux DevTools for two copies of the coin app's StreamManager receiving three bursts of 500 ticker messages. Calling set() for each message logs 1,500 set actions, while buffering messages and flushing them with set([Ticker], rows) logs 3.</video></center>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">StreamManager.ts</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">handleMessage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">msg</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">msg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">in</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">msg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">??=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">msg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">product_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> msg</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">flushTimeout </span><span class="token operator" style="color:rgb(137, 221, 255)">??=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setTimeout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">50</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function-variable function" style="color:rgb(130, 170, 255)">flush</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> buffer </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">buffer </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">flushTimeout </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">in</span><span class="token plain"> buffer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Object</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">buffer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="card_wNtI"><p class="cardTitle_q8VY">探索 coin-app 示例</p><div class="cardLinks_EoYh"><a href="https://stackblitz.com/github/reactive/data-client/tree/master/examples/coin-app?file=src%2Fresources%2FStreamManager.ts%2Csrc%2FgetManagers.ts%2Csrc%2Fresources%2FTicker.ts" target="_blank" rel="noopener noreferrer" class="button button--primary">在 StackBlitz 中打开</a><a href="https://github.com/reactive/data-client/tree/master/examples/coin-app" target="_blank" rel="noopener noreferrer" class="button button--secondary">查看源码</a></div></div><div class="wrapper_ZhQy"><span class="loading_rblT" aria-hidden="true">正在加载演示…</span><iframe width="100%" height="600" title="coin-app 在 StackBlitz 上的演示" class="frame_PtfY"></iframe></div><p style="text-align:center"><a class="button button--secondary button--sm" href="https://dataclient.io/zh-Hans/demos">更多演示</a></p>
<div class="theme-admonition theme-admonition-tip admonition_WCGJ alert alert--success"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_pbrs"><p>If you filter <a class="" href="https://dataclient.io/zh-Hans/docs/api/DevToolsManager">DevToolsManager</a> actions by schema, a batched write's <code>action.schema</code>
is the Array schema, so match <code>action.schema[0]</code> for <code>[Ticker]</code> rather than the Entity itself.</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="faster-types">Faster TypeScript<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#faster-types" class="hash-link" aria-label="Faster TypeScript的直接链接" title="Faster TypeScript的直接链接" translate="no">​</a></h2>
<p>TypeScript re-checks your code on every keystroke in the editor and on every CI build. In apps with many endpoints,
heavy library types show up as laggy autocomplete, red squiggles that take seconds to appear, and slower builds.
v0.19 makes <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">RestEndpoint</a>, <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource">resource()</a> and <code>.extend()</code> much cheaper
to check, with no code changes on your side. TypeScript still reports every error it reported before
(<a href="https://github.com/reactive/data-client/pull/4173" target="_blank" rel="noopener noreferrer" class="">#4173</a>).</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="faster-types-results">Results<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#faster-types-results" class="hash-link" aria-label="Results的直接链接" title="Results的直接链接" translate="no">​</a></h3>
<p>Our heaviest stress test, a file of 150 RestEndpoints with long paths, <code>.extend()</code> and <code>.paginated()</code>, now checks
<strong>2x faster on TypeScript 6</strong> and <strong>2.2x faster on TypeScript 7</strong>, using about <strong>40% less memory</strong>. All numbers compare
the published v0.18.1 packages with v0.19; check times are the best of 10 runs.</p>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">Checking 150 RestEndpoints with long paths</figcaption><div class="bars_HVEW" style="--perf-one:41.66666666666667%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">TypeScript 6</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:80.5976430976431%;--perf-split:51.69712793733681%"></span></span><span class="text--bold">1.9x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->3.83<!-- --> <!-- -->s<!-- --> → <!-- -->v0.19<!-- --> <strong>1.98<!-- --> <!-- -->s</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">TypeScript 7</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:90.57971014492755%;--perf-split:45.99999999999999%"></span></span><span class="text--bold">2.2x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->1.5<!-- --> <!-- -->s<!-- --> → <!-- -->v0.19<!-- --> <strong>0.69<!-- --> <!-- -->s</strong></span></span></div></div></figure>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">Memory for the same file</figcaption><div class="bars_HVEW" style="--perf-one:41.66666666666667%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">TypeScript 6</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:72.07740916271722%;--perf-split:57.80821917808219%"></span></span><span class="text--bold">1.7x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->365<!-- --> <!-- -->MB<!-- --> → <!-- -->v0.19<!-- --> <strong>211<!-- --> <!-- -->MB</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">TypeScript 7</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:71.61458333333334%;--perf-split:58.18181818181818%"></span></span><span class="text--bold">1.7x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->220<!-- --> <!-- -->MB<!-- --> → <!-- -->v0.19<!-- --> <strong>128<!-- --> <!-- -->MB</strong></span></span></div></div></figure>
<p>Endpoint-heavy code does much less type work. Type instantiations are TypeScript's unit of work: they're
deterministic, so they compare cleanly across machines. Union does more work than in v0.18, because v0.19 now
<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-set" class="">type-checks set() values</a> (see below).</p>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">Type instantiations by stress test</figcaption><div class="bars_HVEW" style="--perf-one:41.48418491484185%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Long paths</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:100%;--perf-split:41.48418491484185%"></span></span><span class="text--bold">2.4x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->822<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>341<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Typical app</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:62.53586084177651%;--perf-split:66.33663366336634%"></span></span><span class="text--bold">1.5x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->20.2<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>13.4<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">React hooks</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:49.30497387419728%;--perf-split:84.13793103448275%"></span></span><span class="text--bold">1.2x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->145<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>122<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Vue</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:54.90295931647145%;--perf-split:75.5591054313099%"></span></span><span class="text--bold">1.3x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->62.6<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>47.3<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">300 fields</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:55.09618309002433%;--perf-split:75.29411764705883%"></span></span><span class="text--bold">1.3x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->17<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>12.8<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Schemas</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:49.29641309115144%;--perf-split:84.15254237288136%"></span></span><span class="text--bold">1.2x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->118<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>99.3<!-- --> <!-- -->K</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Union</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:23.189917033141402%;--perf-split:178.88888888888889%"></span><span class="shortfall_TA8N" style="left:23.189917033141402%;width:18.294267881700442%"></span></span><span class="worse_OhAz">0.6x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->9<!-- --> <!-- -->K<!-- --> → <!-- -->v0.19<!-- --> <strong>16.1<!-- --> <!-- -->K</strong></span></span></div></div></figure>
<p>Hover or tap a cell for exact numbers.</p>
<div class="scroll_C2fg"><table class="perfTable_gnxQ"><thead><tr><th></th><th>TS 6 check time</th><th>TS 7 check time</th><th>TS 6 memory</th></tr></thead><tbody><tr><th scope="row">Long paths<div class="description_oO4J">150 RestEndpoints with 6-param paths, <code>.extend()</code> and <code>.paginated()</code></div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:51.697127937336816%"></span></div><span class="better_Bdvc">-48%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">3.83<!-- -->s<!-- --> →<!-- --> <strong>1.98<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:46%"></span></div><span class="better_Bdvc">-54%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">1.5<!-- -->s<!-- --> →<!-- --> <strong>0.69<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:57.80821917808219%"></span></div><span class="better_Bdvc">-42%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">365<!-- -->MB<!-- --> →<!-- --> <strong>211<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">Typical app<div class="description_oO4J">A few resources with <code>.extend()</code>, <code>.paginated()</code> and hooks</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:100%"></span></div><span class="same_qjOp">same</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.42<!-- -->s<!-- --> →<!-- --> <strong>0.42<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:85.48387096774194%"></span></div><span class="better_Bdvc">-15%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.062<!-- -->s<!-- --> →<!-- --> <strong>0.053<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:97.24770642201835%"></span><span class="barAfter_V9wC" style="width:100%"></span></div><span class="worse_ycwO">+3%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">106<!-- -->MB<!-- --> →<!-- --> <strong>109<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">React hooks<div class="description_oO4J">40 resources through every hook, plus <code>ctrl.fetch()</code> and <code>ctrl.set()</code></div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:90.3225806451613%"></span></div><span class="better_Bdvc">-10%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">1.24<!-- -->s<!-- --> →<!-- --> <strong>1.12<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:92.6829268292683%"></span></div><span class="better_Bdvc">-7%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.41<!-- -->s<!-- --> →<!-- --> <strong>0.38<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:94.01197604790418%"></span></div><span class="better_Bdvc">-6%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">167<!-- -->MB<!-- --> →<!-- --> <strong>157<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">Vue<div class="description_oO4J">The same 40 resources through every composable</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:100%"></span></div><span class="same_qjOp">same</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.68<!-- -->s<!-- --> →<!-- --> <strong>0.68<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:88.23529411764704%"></span></div><span class="better_Bdvc">-12%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.17<!-- -->s<!-- --> →<!-- --> <strong>0.15<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:95.86206896551724%"></span></div><span class="better_Bdvc">-4%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">145<!-- -->MB<!-- --> →<!-- --> <strong>139<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">300 fields<div class="description_oO4J">One Entity with 300 fields, read and updated 100 times</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:86.36363636363636%"></span></div><span class="better_Bdvc">-14%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.44<!-- -->s<!-- --> →<!-- --> <strong>0.38<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:60.465116279069775%"></span></div><span class="better_Bdvc">-40%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.086<!-- -->s<!-- --> →<!-- --> <strong>0.052<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:90.990990990991%"></span></div><span class="better_Bdvc">-9%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">111<!-- -->MB<!-- --> →<!-- --> <strong>101<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">Schemas<div class="description_oO4J">All, Query, Invalidate, Array, Object and Collection</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:97.27272727272727%"></span></div><span class="better_Bdvc">-3%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">1.1<!-- -->s<!-- --> →<!-- --> <strong>1.07<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:86.11111111111111%"></span></div><span class="better_Bdvc">-14%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.36<!-- -->s<!-- --> →<!-- --> <strong>0.31<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:96.15384615384616%"></span></div><span class="better_Bdvc">-4%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">156<!-- -->MB<!-- --> →<!-- --> <strong>150<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">Union<div class="description_oO4J">A 30-member Union in a Collection and Values</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:97.61904761904762%"></span></div><span class="better_Bdvc">-2%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.42<!-- -->s<!-- --> →<!-- --> <strong>0.41<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:95.77464788732397%"></span></div><span class="better_Bdvc">-4%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.071<!-- -->s<!-- --> →<!-- --> <strong>0.068<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:94.39252336448598%"></span></div><span class="better_Bdvc">-6%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">107<!-- -->MB<!-- --> →<!-- --> <strong>101<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">set() values<div class="description_oO4J">1000 <code>ctrl.set()</code> calls on a 30-member Union, a Collection of it and a 300-field Entity</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:71.81208053691276%"></span></div><span class="better_Bdvc">-28%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">1.49<!-- -->s<!-- --> →<!-- --> <strong>1.07<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:46.29629629629629%"></span></div><span class="better_Bdvc">-54%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">0.54<!-- -->s<!-- --> →<!-- --> <strong>0.25<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:74.43181818181817%"></span></div><span class="better_Bdvc">-26%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">176<!-- -->MB<!-- --> →<!-- --> <strong>131<!-- -->MB</strong></span></span></td></tr><tr><th scope="row">set() updaters<div class="description_oO4J">1000 <code>ctrl.set(Union, args, prev =&gt; ...)</code> updaters on a 30-member Union</div></th><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:100%"></span><span class="barAfter_V9wC" style="width:95.8100558659218%"></span></div><span class="better_Bdvc">-4%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">3.58<!-- -->s<!-- --> →<!-- --> <strong>3.43<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:90.27027027027026%"></span><span class="barAfter_V9wC" style="width:100%"></span></div><span class="worse_ycwO">+11%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">1.67<!-- -->s<!-- --> →<!-- --> <strong>1.85<!-- -->s</strong></span></span></td><td class="anchor_tRSI" tabindex="0"><div class="cell_YlFy"><div class="bars_qVXI" aria-hidden="true"><span class="barBefore_uor8" style="width:99.21875%"></span><span class="barAfter_V9wC" style="width:100%"></span></div><span class="worse_ycwO">+1%</span></div><span class="tip_ZJ8Q tip_kDq8"><span class="bubble_XBbb">381<!-- -->MB<!-- --> →<!-- --> <strong>384<!-- -->MB</strong></span></span></td></tr></tbody></table></div>
<p>The set() rows measure <a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-set" class="">typed set() values</a>, which v0.18 didn't check at all. Plain values still check
faster than before, and updater functions on large Unions check in about the same time even though TypeScript now
checks each updater's return value (<a href="https://github.com/reactive/data-client/pull/4179" target="_blank" rel="noopener noreferrer" class="">#4179</a>).</p>
<p>Small files are dominated by TypeScript's fixed startup cost (loading <code>lib.dom.d.ts</code> alone takes about 100MB), so
their time and memory barely move. The savings add up as a codebase grows.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="faster-types-how">What changed<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#faster-types-how" class="hash-link" aria-label="What changed的直接链接" title="What changed的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><code>.extend()</code> and <code>.paginated()</code> are shared across all endpoints instead of re-created for each endpoint type.</li>
<li class="">Endpoint options infer as plain object types, so TypeScript stops rebuilding them at every use.</li>
<li class="">Path parameters like <code>/users/:id</code> are read in a single pass.</li>
</ul>
<p>Before shipping, we turned off every <code>@ts-expect-error</code> in the test suite on TypeScript 4.0 through 7 and confirmed
every error still appears in the same place.</p>
<p>On TypeScript 5.x and earlier, a <code>process(value, params)</code> method passed to <code>.extend()</code> also no longer fails with
"implicitly has an 'any' type" under <code>strict</code>.</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-improvements">Other improvements<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#other-improvements" class="hash-link" aria-label="Other improvements的直接链接" title="Other improvements的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="typed-set">Typed set() values<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-set" class="hash-link" aria-label="Typed set() values的直接链接" title="Typed set() values的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set">Controller.set()</a> previously accepted any value for a schema, so a typo or a wrong
field type only surfaced as bad data at runtime. Values are now typed by the schema: an
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a> takes its fields, while a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>, <a class="" href="https://dataclient.io/zh-Hans/rest/api/All">All</a> or
Array takes a list of rows. Every field is optional, since <code>set()</code> merges into what is already stored, and
numbers and strings are interchangeable just like in API responses.
<a href="https://github.com/reactive/data-client/pull/4133" target="_blank" rel="noopener noreferrer" class="">#4133</a></p>
<p>Hover the red underlines to see each error.</p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh small_xksL"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">Todo</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">updateTodos</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Controller </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> schema </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> TodoResource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./Todo'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">updateTodos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ctrl</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ✅ rows are partial Todos; ids may be strings or numbers</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">completed </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'first'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ❌ All takes a list of rows</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">All</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">42</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ❌ completed is a boolean</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'yes'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ❌ Todo has no done field</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> done</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ❌ updaters must return Todo fields</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">completed </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span>
</span></pre></div></div></div></div></div>
<p>A <a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> takes the input of the schema it wraps, since <code>set()</code> normalizes that schema rather than
reversing <code>process()</code>. When each member declares its discriminator as a literal (like <code>readonly type = 'post'</code>), a
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a> row is checked against the member it selects, so it can't mix fields from different members; see <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set">Unions</a>.</p>
<p>If code that previously compiled now fails here, it was writing data its schema doesn't describe. Fix the value,
or widen the Entity's field types if the data really can take that shape.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="set-invalidate">Delete one entity with set()<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#set-invalidate" class="hash-link" aria-label="Delete one entity with set()的直接链接" title="Delete one entity with set()的直接链接" translate="no">​</a></h3>
<p>Passing an <a class="" href="https://dataclient.io/zh-Hans/rest/api/Invalidate">Invalidate</a> schema to <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set-array">Controller.set()</a> deletes the
entity its row identifies, but the single form was a TypeScript error, so code wrapped it in a one-row batch. It now
type-checks, with the row typed by the Entity's fields
(<a href="https://github.com/reactive/data-client/pull/4230" target="_blank" rel="noopener noreferrer" class="">#4230</a>):</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Invalidate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Invalidate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>Like batch <code>set()</code>, it takes no <code>args</code> and no updater function.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="extend-process-params">Typed process() params<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#extend-process-params" class="hash-link" aria-label="Typed process() params的直接链接" title="Typed process() params的直接链接" translate="no">​</a></h3>
<p>A <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#process">process()</a> method passed to <code>new RestEndpoint()</code>,
<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#extend">.extend()</a> or <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#extend">resource().extend()</a> got <code>params</code> typed as
<code>any</code>, so reading a parameter the endpoint doesn't have compiled and returned <code>undefined</code> at runtime. <code>params</code> and
<code>body</code> are now typed from the endpoint, including a <code>path</code> set in the same <code>.extend()</code> call
(<a href="https://github.com/reactive/data-client/pull/4183" target="_blank" rel="noopener noreferrer" class="">#4183</a>, <a href="https://github.com/reactive/data-client/pull/4184" target="_blank" rel="noopener noreferrer" class="">#4184</a>):</p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUserById </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> getUser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/by-id/:userId'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// @ts-expect-error 'id' is not a param of '/users/by-id/:userId'</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    params</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> userId </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div></div></div>
<p>When every param is optional, <code>params</code> may be <code>undefined</code>, so read it with <code>params?.page</code>.</p>
<p>This can surface new TypeScript errors in existing <code>process()</code> methods. Each one marks a read that could be <code>undefined</code>
or throw at runtime, so fix the param name or add the missing check.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="typed-optimistic-response">Typed optimistic responses<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-optimistic-response" class="hash-link" aria-label="Typed optimistic responses的直接链接" title="Typed optimistic responses的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#getoptimisticresponse">getOptimisticResponse()</a> could return anything unless the endpoint had
a typed <code>process()</code>, so a wrong field type only showed up as bad data in the UI until the server responded. The return
value is now checked against the endpoint's schema, like a <a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typed-set" class="">typed set() value</a>: an Entity takes any of its
fields, and a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> takes a list of them
(<a href="https://github.com/reactive/data-client/pull/4198" target="_blank" rel="noopener noreferrer" class="">#4198</a>):</p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Todo</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  completed </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> toggleTodo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  method</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'PATCH'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// @ts-expect-error completed is a boolean; 'false' is truthy, so the checkbox would stay checked</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">completed </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'false'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'true'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div></div></div>
<p>This can surface new TypeScript errors in existing <code>getOptimisticResponse()</code> methods. Each one marks a value that would
be stored with the wrong type until the server responds, so return the field's real type (here <code>!todo.completed</code>).</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="query-collection-push">Typed push() on sorted Collections<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#query-collection-push" class="hash-link" aria-label="Typed push() on sorted Collections的直接链接" title="Typed push() on sorted Collections的直接链接" translate="no">​</a></h3>
<p>Wrapping a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> in a <a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> to sort or filter it made
<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#push">push</a>, <code>unshift</code> and <code>remove</code> reject every body except <code>FormData</code>, though they add to the
list at runtime. The body is now typed from the Collection's Entity, so the cast can go and a wrong field is a
TypeScript error. The same applies to a Collection wrapped in <a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy">Lazy</a>
(<a href="https://github.com/reactive/data-client/pull/4226" target="_blank" rel="noopener noreferrer" class="">#4226</a>).</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getPosts </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./getPosts'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useAddPost</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> author</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getPosts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">push</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> author </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getPosts </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./getPosts'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useAddPost</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> author</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getPosts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">push</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> author </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>where <code>getPosts</code> sorts its Collection with a Query:</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">getPosts.ts</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Post</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  group </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  author </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getPosts </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:group/posts'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> orderBy</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'title'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'author'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> nonFilterArgumentKeys</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex">orderBy</span><span class="token regex regex-delimiter">/</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">posts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> orderBy </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> orderBy</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'title'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'author'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      orderBy </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">posts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">sort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">a</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> a</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">orderBy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">localeCompare</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">b</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">orderBy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> posts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="create-formdata">FormData in resource().create<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#create-formdata" class="hash-link" aria-label="FormData in resource().create的直接链接" title="FormData in resource().create的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/resource">resource()</a>'s <code>create</code> sends a <code>FormData</code> body as-is, like <code>update</code>, <code>partialUpdate</code> and
<a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#push">getList.push</a>, but its type only allowed an object, so submitting a form needed a cast
(<a href="https://github.com/reactive/data-client/pull/4235" target="_blank" rel="noopener noreferrer" class="">#4235</a>). Drop the cast:</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">form</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">  </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onSubmit</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">e </span><span class="token tag script language-javascript arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">    e</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(130, 170, 255)">preventDefault</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">    ctrl</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(130, 170, 255)">fetch</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript maybe-class-name" style="color:rgb(255, 85, 114)">PostResource</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">create</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">new</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript class-name" style="color:rgb(255, 203, 107)">FormData</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">e</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">currentTarget</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">as</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript builtin" style="color:rgb(130, 170, 255)">any</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">  </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">form</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)">  </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onSubmit</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">e </span><span class="token tag script language-javascript arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">    e</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(130, 170, 255)">preventDefault</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">    ctrl</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript method function property-access" style="color:rgb(130, 170, 255)">fetch</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript maybe-class-name" style="color:rgb(255, 85, 114)">PostResource</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">create</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">new</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript class-name" style="color:rgb(255, 203, 107)">FormData</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">e</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">currentTarget</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">  </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token tag" style="color:rgb(255, 85, 114)"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></figure>
<p><code>create</code> is deprecated; <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#push">getList.push</a> is its replacement and takes <code>FormData</code> too.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="vue-getter-args">Vue getter arguments<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-getter-args" class="hash-link" aria-label="Vue getter arguments的直接链接" title="Vue getter arguments的直接链接" translate="no">​</a></h3>
<p>Vue composables like <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useLive">useLive()</a> were typed to accept a
getter function as an argument, but they passed the function itself to the endpoint instead of calling it. Getters now
work the same as refs and <code>computed</code>, and the composable refetches when anything the getter reads changes
(<a href="https://github.com/reactive/data-client/pull/4115" target="_blank" rel="noopener noreferrer" class="">#4115</a>). Drop the <code>computed()</code> wrapper if you only used it to make
arguments reactive:</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> computed </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> props </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(130, 170, 255)">defineProps</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token generic-function generic class-name punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> id</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">:</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> </span><span class="token generic-function generic class-name builtin" style="color:rgb(130, 170, 255)">number</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> </span><span class="token generic-function generic class-name punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> article </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">computed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> props </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token generic-function function" style="color:rgb(130, 170, 255)">defineProps</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token generic-function generic class-name punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> id</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">:</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> </span><span class="token generic-function generic class-name builtin" style="color:rgb(130, 170, 255)">number</span><span class="token generic-function generic class-name" style="color:rgb(255, 203, 107)"> </span><span class="token generic-function generic class-name punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token generic-function generic class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> article </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>This applies to every composable that takes endpoint arguments: <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a>,
<a class="" href="https://dataclient.io/zh-Hans/vue/api/useLive">useLive()</a>, <a class="" href="https://dataclient.io/zh-Hans/vue/api/useCache">useCache()</a>, <a class="" href="https://dataclient.io/zh-Hans/vue/api/useDLE">useDLE()</a>,
<a class="" href="https://dataclient.io/zh-Hans/vue/api/useFetch">useFetch()</a>, <a class="" href="https://dataclient.io/zh-Hans/vue/api/useQuery">useQuery()</a> and <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSubscription">useSubscription()</a>.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="vue-gc">Vue garbage collects by default<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-gc" class="hash-link" aria-label="Vue garbage collects by default的直接链接" title="Vue garbage collects by default的直接链接" translate="no">​</a></h3>
<p>Vue's <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin#gcPolicy">DataClientPlugin</a> only removed unused data if you passed a <code>gcPolicy</code>
yourself. It now defaults to <code>new GCPolicy()</code>, the same as React's <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a>, so you can
drop the option unless you customize it (<a href="https://github.com/reactive/data-client/pull/4148" target="_blank" rel="noopener noreferrer" class="">#4148</a>).</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> GCPolicy </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> gcPolicy</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">GCPolicy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> DataClientPlugin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>Data is removed only when no mounted component reads it <em>and</em> twice its freshness lifetime has passed since it was
fetched (at least two minutes). A sweep checks every five minutes. Anything a component reads again before then is
back in use.</p>
<center><div style="max-width:640px"></div></center>
<p>A component that mounts after removal treats the data as never fetched: <a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> fetches
it again, while <a class="" href="https://dataclient.io/zh-Hans/vue/api/useCache">useCache()</a> returns <code>undefined</code>. To keep unused data longer or sweep less often,
pass your own <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin#gcPolicy">gcPolicy</a>.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="vue-stale-while-revalidate">Vue stale-while-revalidate<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#vue-stale-while-revalidate" class="hash-link" aria-label="Vue stale-while-revalidate的直接链接" title="Vue stale-while-revalidate的直接链接" translate="no">​</a></h3>
<p>When a component mounts with data that is <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/expiry-policy#stale">stale</a> but still valid, Vue
<a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense">useSuspense()</a> now renders it right away and refetches in the background, like React. Before,
it showed the <code>&lt;Suspense&gt;</code> fallback until the refetch finished (<a href="https://github.com/reactive/data-client/pull/4169" target="_blank" rel="noopener noreferrer" class="">#4169</a>).</p>
<center><video width="720" controls="" muted="" playsinline="" loop="" aria-label="Two Vue components side by side, before and after v0.19. Both show Loading on first mount. After unmounting and waiting until the price goes stale, remounting shows Loading again in the before version, while the after version shows the stale price right away and refetches in the background."><source src="/zh-Hans/videos/blog/vue-suspense-stale.mp4" type="video/mp4">Two Vue components side by side, before and after v0.19. Both show Loading on first mount. After unmounting and waiting until the price goes stale, remounting shows Loading again in the before version, while the after version shows the stale price right away and refetches in the background.</video></center>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="entity-pk-args">Entity classes typecheck as EntityInterface<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#entity-pk-args" class="hash-link" aria-label="Entity classes typecheck as EntityInterface的直接链接" title="Entity classes typecheck as EntityInterface的直接链接" translate="no">​</a></h3>
<p>Helpers typed to accept any Entity with <code>EntityInterface</code> rejected Entity classes, because
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#pk">Entity.pk()</a> typed its <code>args</code> as a mutable array. It is now <code>readonly any[]</code>, so this
typechecks (<a href="https://github.com/reactive/data-client/pull/4149" target="_blank" rel="noopener noreferrer" class="">#4149</a>):</p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> EntityInterface </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">entityName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> EntityInterface</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">entityName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div></div></div>
<p>If you override <code>static pk()</code> and type <code>args</code> as a mutable array, it still compiles, but a future breaking release
will require <code>readonly</code>; <a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-pk-args" class="">update it now</a>.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="deleted-entity-undefined">Deleted entities read as undefined<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#deleted-entity-undefined" class="hash-link" aria-label="Deleted entities read as undefined的直接链接" title="Deleted entities read as undefined的直接链接" translate="no">​</a></h3>
<p>When an entity was deleted and its refetch failed, <a class="" href="https://dataclient.io/zh-Hans/docs/api/useCache">useCache()</a> and <a class="" href="https://dataclient.io/zh-Hans/docs/api/useDLE">useDLE()</a>
(React and Vue) returned an internal <code>Symbol</code> as data. A <code>Symbol</code> is truthy, so the usual "not loaded yet" guard let it
through and the component rendered as if it had an entity
(<a href="https://github.com/reactive/data-client/pull/4150" target="_blank" rel="noopener noreferrer" class="">#4150</a>):</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TodoDetail</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// a deleted todo used to get past this guard, so todo.title.trim() threw</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">TodoPlaceholder</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">trim</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>Now <code>data</code> is <code>undefined</code>, matching its type and <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#get">Controller.get()</a>. The same applies to
<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#getResponse">Controller.getResponse()</a> and
<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#fetchIfStale">Controller.fetchIfStale()</a>, for example in custom <a class="" href="https://dataclient.io/zh-Hans/docs/api/Manager">Managers</a>.</p>
<p>If you worked around this, the workaround can go. A plain truthiness check is enough:</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TodoDetail</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">todo </span><span class="token operator" style="color:rgb(137, 221, 255)">||</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">typeof</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'symbol'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">TodoPlaceholder</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">trim</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TodoDetail</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">TodoPlaceholder</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">trim</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>To show something specific when the refetch failed (for example a 404 after deletion), read <code>error</code> from
<a class="" href="https://dataclient.io/zh-Hans/docs/api/useDLE">useDLE()</a> rather than inspecting <code>data</code>.</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="devtools-perf">Faster Redux DevTools<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#devtools-perf" class="hash-link" aria-label="Faster Redux DevTools的直接链接" title="Faster Redux DevTools的直接链接" translate="no">​</a></h3>
<p>With the <a class="" href="https://dataclient.io/zh-Hans/docs/getting-started/debugging">Redux DevTools</a> extension open, every store update in development
serializes the whole store for the extension, and each timestamp in it was formatted the slow way. Large stores or
frequent updates, like polling, live data or many <code>controller.set()</code> calls, made the page stutter. Each update now
serializes <strong>40-60x faster</strong>, and timestamps still read like <code>10:42:07.123 AM</code>
(<a href="https://github.com/reactive/data-client/pull/4163" target="_blank" rel="noopener noreferrer" class="">#4163</a>). Production builds don't include DevTools, so they are
unaffected.</p>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">DevTools serialization per store update</figcaption><div class="bars_HVEW" style="--perf-one:1.6666666666666663%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">50 entities</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:100%;--perf-split:1.6666666666666663%"></span></span><span class="text--bold">60x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->18.6<!-- --> <!-- -->ms<!-- --> → <!-- -->v0.19<!-- --> <strong>0.31<!-- --> <!-- -->ms</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">500 entities</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:67%;--perf-split:2.487562189054726%"></span></span><span class="text--bold">40x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">v0.18<!-- --> <!-- -->201<!-- --> <!-- -->ms<!-- --> → <!-- -->v0.19<!-- --> <strong>5<!-- --> <!-- -->ms</strong></span></span></div></div></figure>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">Migration guide<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#migration-guide" class="hash-link" aria-label="Migration guide的直接链接" title="Migration guide的直接链接" translate="no">​</a></h2>
<!-- -->
<p>This upgrade requires updating all package versions simultaneously.</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.19.0 @data-client/rest@^0.19.0 @data-client/endpoint@^0.19.0 @data-client/core@^0.19.0 @data-client/vue@^0.19.0 @data-client/test@^0.19.0 @data-client/img@^0.19.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.19.0 @data-client/rest@^0.19.0 @data-client/endpoint@^0.19.0 @data-client/core@^0.19.0 @data-client/vue@^0.19.0 @data-client/test@^0.19.0 @data-client/img@^0.19.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.19.0 @data-client/rest@^0.19.0 @data-client/endpoint@^0.19.0 @data-client/core@^0.19.0 @data-client/vue@^0.19.0 @data-client/test@^0.19.0 @data-client/img@^0.19.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/endpoint"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/endpoint@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/core"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/core@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/vue"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/vue@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.19.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.19.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="typescript-4">TypeScript 4.0 or later<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#typescript-4" class="hash-link" aria-label="TypeScript 4.0 or later的直接链接" title="TypeScript 4.0 or later的直接链接" translate="no">​</a></h3>
<p>Skip this section if you already use TypeScript 4.0 or later.</p>
<p>The TypeScript 3.x declarations are removed, since they no longer typechecked on any TypeScript 3.x version. Bump
<code>typescript</code> to <code>^4.0.0</code> or later in your <code>devDependencies</code>. <a href="https://github.com/reactive/data-client/pull/4151" target="_blank" rel="noopener noreferrer" class="">#4151</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="manager-middleware">Manager.middleware is required<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#manager-middleware" class="hash-link" aria-label="Manager.middleware is required的直接链接" title="Manager.middleware is required的直接链接" translate="no">​</a></h3>
<p>Skip this section if your <a class="" href="https://dataclient.io/zh-Hans/docs/api/Manager">Managers</a> already define <code>middleware</code>.</p>
<p><code>getMiddleware()</code> was replaced by the <a class="" href="https://dataclient.io/zh-Hans/docs/api/Manager#middleware">middleware</a> property in
<a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement">v0.14</a>; it's now removed. A Manager that still defines it, or has no
middleware at all, is a TypeScript error, and throws when <code>DataProvider</code> or <code>DataClientPlugin</code> mounts in development.
Rename <code>getMiddleware()</code> to a <code>middleware</code> property:</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'before'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'after'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'before'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'after'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p><a href="https://github.com/reactive/data-client/pull/4382" target="_blank" rel="noopener noreferrer" class="">#4382</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="test-react-0.15">@data-client/test requires @data-client/react 0.15.3<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#test-react-0.15" class="hash-link" aria-label="@data-client/test requires @data-client/react 0.15.3的直接链接" title="@data-client/test requires @data-client/react 0.15.3的直接链接" translate="no">​</a></h3>
<p>Skip this section if you don't use <a href="https://www.npmjs.com/package/@data-client/test" target="_blank" rel="noopener noreferrer" class="">@data-client/test</a>.</p>
<p><code>@data-client/test</code> now builds on <code>@data-client/react/mock</code>, which first loads in Jest and other CommonJS tests in
<code>@data-client/react</code> 0.15.3, so support for 0.12 through 0.15.2 is dropped. Upgrade <code>@data-client/react</code> to the same
version as <code>@data-client/test</code>, as the install command above does. Fixture types imported from <code>@data-client/test</code> and
from <code>@data-client/react/mock</code> are now the same types. <a href="https://github.com/reactive/data-client/pull/4414" target="_blank" rel="noopener noreferrer" class="">#4414</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="dc-global"><code>__DC_CONTROLLERS__</code> is now <code>__DC__</code><a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#dc-global" class="hash-link" aria-label="dc-global的直接链接" title="dc-global的直接链接" translate="no">​</a></h3>
<p>Skip this section if no debugging script or tool of yours reads <code>globalThis.__DC_CONTROLLERS__</code>.</p>
<p>In development, <a class="" href="https://dataclient.io/zh-Hans/docs/api/DevToolsManager#controllers">DevToolsManager</a> now puts the store on <code>globalThis.__DC__</code>,
whose <code>controller</code> and <code>actions</code> read the page's store, instead of the <code>__DC_CONTROLLERS__</code> Map. With several stores,
<code>__DC__.stores</code> lists their keys and setting <code>__DC__.store</code> picks one.</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-js codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-js codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">__DC_CONTROLLERS__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Data Client: My App'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-js codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-js codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">__DC__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">store</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Data Client: My App'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// only needed with several stores</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">__DC__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p><a href="https://github.com/reactive/data-client/pull/4435" target="_blank" rel="noopener noreferrer" class="">#4435</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="future-releases">Get ready for future releases<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-releases" class="hash-link" aria-label="Get ready for future releases的直接链接" title="Get ready for future releases的直接链接" translate="no">​</a></h3>
<p>Nothing here is needed to upgrade to 0.19; your code keeps working as is. Each item will break in a future release,
so updating now makes that upgrade a no-op.</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="future-pk-args">Entity.pk() args are readonly<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-pk-args" class="hash-link" aria-label="Entity.pk() args are readonly的直接链接" title="Entity.pk() args are readonly的直接链接" translate="no">​</a></h4>
<p>Skip this if you don't override <code>static pk()</code> with a typed <code>args</code> parameter.</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#pk">Entity.pk()</a> now types <code>args</code> as <code>readonly any[]</code>. Overrides that annotate it as a mutable
array still compile for now, but a future release will require <code>readonly</code>.</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">value</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">id</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">-</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">args</span><span class="token template-string interpolation operator" style="color:rgb(137, 221, 255)">?.</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token template-string interpolation number" style="color:rgb(247, 140, 108)">0</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token template-string interpolation operator" style="color:rgb(137, 221, 255)">?.</span><span class="token template-string interpolation">org</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">value</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">id</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)">-</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">args</span><span class="token template-string interpolation operator" style="color:rgb(137, 221, 255)">?.</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token template-string interpolation number" style="color:rgb(247, 140, 108)">0</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token template-string interpolation operator" style="color:rgb(137, 221, 255)">?.</span><span class="token template-string interpolation">org</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="future-create-data-client">Vue createDataClient()<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-create-data-client" class="hash-link" aria-label="Vue createDataClient()的直接链接" title="Vue createDataClient()的直接链接" translate="no">​</a></h4>
<p>Skip this if you install the store with <code>app.use(DataClientPlugin)</code>.</p>
<p><code>createDataClient()</code> and <code>ProvidedDataClient</code> are internal to <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin">DataClientPlugin</a> and will
stop being exported. Install the plugin instead, and read the controller with
<a class="" href="https://dataclient.io/zh-Hans/vue/api/useController">useController()</a>. <a href="https://github.com/reactive/data-client/pull/4193" target="_blank" rel="noopener noreferrer" class="">#4193</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createDataClient </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> controller </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createDataClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> managers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> initialState </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> managers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> initialState </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// in a component's setup()</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="future-wait-for-next-update">Vue renderDataCompose() waitForNextUpdate()<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#future-wait-for-next-update" class="hash-link" aria-label="Vue renderDataCompose() waitForNextUpdate()的直接链接" title="Vue renderDataCompose() waitForNextUpdate()的直接链接" translate="no">​</a></h4>
<p>Skip this if your Vue tests don't call <code>waitForNextUpdate()</code>.</p>
<p><code>waitForNextUpdate()</code> from <a class="" href="https://dataclient.io/zh-Hans/vue/guides/unit-testing-composables#renderdatacompose-api">renderDataCompose()</a> gives up
silently after 1 second, so a test can pass while the composable is still suspended. It will be removed. <code>await</code> the
result instead, and call <code>allSettled()</code> after changing props or calling the controller; it now also waits for the
fetch a prop change starts. <a href="https://github.com/reactive/data-client/pull/4221" target="_blank" rel="noopener noreferrer" class="">#4221</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> waitForNextUpdate </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">renderDataCompose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">props</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resolverFixtures </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">waitForNextUpdate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> article </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">6</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">waitForNextUpdate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> allSettled </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">renderDataCompose</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">props</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resolverFixtures </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> article </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> result</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">props</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">6</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">allSettled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">Upgrade support<a href="https://dataclient.io/zh-Hans/blog/2026/10/03/v0.19-batch-set#upgrade-support" class="hash-link" aria-label="Upgrade support的直接链接" title="Upgrade support的直接链接" translate="no">​</a></h3>
<p>As usual, if you have any troubles or questions, feel free to join our <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> or <a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">file a bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>AI 智能体</category>
            <category>Manager</category>
            <category>Schema</category>
        </item>
        <item>
            <title><![CDATA[v0.18：Scalar、类型化文件下载、过滤感知的 Collection]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads</link>
            <guid>https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads</guid>
            <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[借助 Scalar 实现随视角（lens）变化的实体字段，通过 RestEndpoint content 实现类型化文件下载，自动处理二进制响应，以及 resource() 的 nonFilterArgumentKeys 让集合感知排序参数]]></description>
            <content:encoded><![CDATA[<p>v0.18 聚焦于三件事：对随请求上下文变化的值进行更丰富的数据建模、更简单的类型化下载，以及更贴近真实 API 过滤条件的集合匹配。</p>
<p><strong>新特性：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#scalar">Scalar schema</a> - 随视角（lens）变化的实体字段（例如特定投资组合的数值），且永不修改底层实体</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#content-property">RestEndpoint <code>content</code> 属性</a> - 只用一个属性即可实现类型化文件下载、文本响应和流式传输</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#non-filter-argument-keys">resource() <code>nonFilterArgumentKeys</code></a> - 排序/分页参数不再把你的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 拆散</li>
</ul>
<p><strong>其他改进：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#binary-auto-detection">二进制 Content-Type 自动检测</a> - 图片、PDF 及其他二进制响应无需任何配置即可自动处理（<a href="https://github.com/reactive/data-client/pull/3868" target="_blank" rel="noopener noreferrer" class="">#3868</a>）</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection 扩展方法的 body 类型与 HTTP 方法语义一致</a> - PATCH 扩展方法（<code>.move</code>、<code>.remove</code>）接受部分 body；独立的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">RestEndpoint</a> 会从 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 的实体 schema 推导出类型化的 body（<a href="https://github.com/reactive/data-client/pull/3910" target="_blank" rel="noopener noreferrer" class="">#3910</a>）</li>
<li class="">从 <code>@data-client/endpoint</code> 和 <code>@data-client/rest</code> 导出 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection"><code>CollectionOptions</code></a>，用于类型化地构造 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>（<a href="https://github.com/reactive/data-client/pull/3904" target="_blank" rel="noopener noreferrer" class="">#3904</a>）</li>
</ul>
<div data-playground="true" class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA"><div class="playgroundTextEdit_rt2K"><div class="playgroundHeader_Zx4K fixturesHeader_kjOp small_xksL"><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 20V4"></path><path d="m3 8 4-4 4 4"></path><path d="M17 4v16"></path><path d="m21 16-4 4-4-4"></path></svg>Fixtures</div><div class="fixtureBlock_mpRK"><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/companies</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ companiesByPortfolio[portfolio] ?? []</span><span class="pill_f9VU fixtureDelay_zwlo">150 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/companies/columns</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ (companiesByPortfolio[portfolio] ?? []).map(({ id, pct_equity, shares }) =&gt; ({ id, pct_equity, shares }))</span><span class="pill_f9VU fixtureDelay_zwlo">150 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div></div><div class="playgroundHeader_Zx4K clickable_YHiX small_xksL"><span class="arrow_tivA down_oRky">▶</span>api/Company</div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Scalar </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Company</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  price </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  pct_equity </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  shares </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> PortfolioScalar </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Scalar</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">lens</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> args </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">portfolio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'portfolio'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  entity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Company</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Company</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  pct_equity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> PortfolioScalar</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  shares</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> PortfolioScalar</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getCompanies </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/companies'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> portfolio</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// `portfolio` is a lens, not a filter — the returned Company list is the same</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// regardless of lens. Dropping it from `argsKey` collapses every portfolio to</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// one Collection pk, so `Collection.queryKey()` finds the list on every</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// switch and `useSuspense` reuses it without refetching.</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Company</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">argsKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getPortfolioColumns </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/companies/columns'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> portfolio</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">PortfolioScalar</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">argsKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> portfolio </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> portfolio</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> portfolio </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div><div class="playgroundHeader_Zx4K clickable_YHiX small_xksL"><span class="arrow_tivA right_vs_C">▶</span>CompanyGrid</div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundHeader_Zx4K clickable_YHiX small_xksL"><span class="arrow_tivA right_vs_C">▶</span>PortfolioGrid</div><div class="playgroundEditor_lYwu hidden_Hh8i"></div></div><div class="previewWrapper_edd2"><div class="playgroundHeader_Zx4K previewHeader_MW_M"><span class="liveLabel_MHnJ"><span class="liveLabelText_k6qc">实时预览</span></span><span class="routerSlot_CTii"></span><span class="previewControls_oxCt"><button type="button" class="clean-btn headerButton_h2KM storeHeaderToggle_ToEw" title="显示 Store" aria-label="Store" aria-pressed="false" data-store-toggle="true" disabled=""><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"></ellipse><path d="M4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5"></path><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"></path></svg></button></span></div><div class="playgroundResult_tefG"><div class="playgroundPreview_rk9R"></div><div class="debugToggle_zlro" data-store-toggle="true">Store<span class="arrow_tivA right_vs_C vertical_OMeC">▶</span></div></div></div></div></div>
<p>这个示例展示了同一批 <code>Company</code> 实体通过不同的投资组合视角进行渲染。稳定的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a> 字段会被复用，而随视角变化的值则从独立的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar"><code>Scalar</code></a> 单元格中选取。</p>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#migration-guide">破坏性变更：</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#denormalize-delegate">Schema.denormalize() 接收 delegate</a> - <code>denormalize(input, args, unvisit)</code> → <code>denormalize(input, delegate)</code>。仅影响自定义 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">Schema</a> 实现。</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#normalize-delegate">Schema.normalize() 接收 delegate</a> - <code>normalize(input, parent, key, args, visit, delegate)</code> → <code>normalize(input, parent, key, delegate)</code>。仅影响自定义 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">Schema</a> 实现。</li>
</ul>
<p>**在使用 AI 智能体？**安装迁移 skill——它会运行 codemod，为依赖参数的 schema 注册
<a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>argsKey</code></a>，并处理 codemod 无法覆盖的情况（类字段、动态方法赋值、SFC <code>&lt;script&gt;</code> 块、自定义辅助函数）：</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs tabs_qwsy"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">Skills CLI</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">OpenSkills</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx skills </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> data-client-v0.18-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx openskills </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> reactive/data-client/.agents/skills/data-client-v0.18-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div></div></div>
<p>否则，直接运行 <a href="https://dataclient.io/zh-Hans/assets/files/v0.18-57a9e93e47ddbc37fc4ab436a1aa882b.js" target="_blank" class="">codemod</a>——它覆盖了常见情况：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.18.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="scalar">Scalar<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#scalar" class="hash-link" aria-label="Scalar的直接链接" title="Scalar的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar">Scalar</a> 用于处理那些取值依赖运行时“视角”（lens）的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a> 字段——比如当前选中的投资组合、货币或区域设置。多个组件可以同时通过不同视角渲染<strong>同一个</strong>实体，各自看到正确的值，而实体本身始终不变。随视角变化的值存放在单独的单元格表中，并在反规范化时根据 endpoint 参数进行关联。</p>
<p>切换投资组合时 <code>name</code> 和 <code>price</code> 的引用保持稳定，因为 <code>Company</code> 实体本身从未改变——改变的只是当前视角所选中的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar"><code>Scalar</code></a> 单元格。同一个 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar"><code>Scalar</code></a>
实例既可以作为 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#schema"><code>Entity.schema</code></a> 字段使用（父实体从访问过程中推断），也可以独立用在 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Values"><code>Values</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Array"><code>[Scalar]</code></a>
或 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection"><code>Collection([Scalar])</code></a> 中，以实现低成本的仅刷新列操作（通过
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar#entity"><code>entity</code></a> 显式绑定实体）。单元格的 pk 由映射键派生，或通过
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar#entityPk"><code>Scalar.entityPk()</code></a> 得到，后者默认使用 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#pk"><code>Entity.pk()</code></a>，因此自定义主键和复合主键无需重写即可正常工作。</p>
<p>规范化后的 store 保持实体稳定，并把视角单元格分开存放：</p>
<div class="language-text codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-text codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">entities['Company']['1'] = {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id: '1',</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  price: 145.20,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  pct_equity: ['1', 'pct_equity', 'Company'],</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  shares: ['1', 'shares', 'Company'],</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">entities['Scalar(portfolio)']['Company|1|A'] = { pct_equity: 0.50, shares: 10000 }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">entities['Scalar(portfolio)']['Company|1|B'] = { pct_equity: 0.30, shares: 6000 }</span><br></div></code></pre></div></div>
<p>示例将 <code>getCompanies</code> 与一个低成本的、仅刷新视角数据的 <code>getPortfolioColumns</code> 配对，二者写入同一个单元格表——完整的缓存行为讲解请参阅 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar">Scalar 文档</a>。</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar"><code>Scalar</code></a> 还实现了 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar#queryKey">queryKey</a>，因此可以直接参与
<a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery">useQuery</a>、<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#get">Controller.get</a> 和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">schema.Query</a>——
即完整的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema#queryable">Queryable</a> 能力——枚举当前视角下的所有单元格。</p>
<p><a href="https://github.com/reactive/data-client/pull/3887" target="_blank" rel="noopener noreferrer" class="">#3887</a> - <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar">Scalar 文档</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="content-property">RestEndpoint <code>content</code> 属性<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#content-property" class="hash-link" aria-label="content-property的直接链接" title="content-property的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">RestEndpoint</a> 现在接受一个 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#content"><code>content</code></a> 属性，用于控制响应体的解析方式。返回类型会根据该值自动推断，并且对于非 JSON 的内容类型，<code>schema</code>
在类型层面被约束为 <code>undefined</code>。</p>
<div class="language-typescript codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-typescript codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> downloadFile </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/files/:id/download'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  content</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'blob'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  dataExpiryLength</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Return type is Blob — inferred from content, no explicit generics needed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> blob</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Blob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">downloadFile</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'123'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>以前，文件下载需要冗长地重写 <code>parseResponse</code>。现在只需一个属性。</p>
<div class="table-scroll"><table><thead><tr><th>值</th><th>解析方式</th><th>返回类型</th></tr></thead><tbody><tr><td><code>'json'</code></td><td><code>response.json()</code></td><td><code>any</code></td></tr><tr><td><code>'blob'</code></td><td><code>response.blob()</code></td><td><code>Blob</code></td></tr><tr><td><code>'text'</code></td><td><code>response.text()</code></td><td><code>string</code></td></tr><tr><td><code>'arrayBuffer'</code></td><td><code>response.arrayBuffer()</code></td><td><code>ArrayBuffer</code></td></tr><tr><td><code>'stream'</code></td><td><code>response.body</code></td><td><code>ReadableStream&lt;Uint8Array&gt;</code></td></tr></tbody></table></div>
<p>将 <code>content</code> 设为非 JSON 的值会在类型层面强制要求 <code>schema: undefined</code>，因为二进制数据无法被规范化。如果不小心使用了可规范化的 schema，运行时检查会给出清晰的错误信息。</p>
<p>可与 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#extend"><code>extend()</code></a> 和<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#inheritance">子类</a>配合使用：</p>
<div class="language-typescript codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-typescript codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Extend a JSON endpoint into a blob downloader</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> download </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> jsonEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  content</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'blob'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Subclass for a reusable blob endpoint type</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">class</span><span class="token plain"> BlobEndpoint</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token constant" style="color:rgb(130, 170, 255)">O</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestGenerics</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  content </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'blob'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p><a href="https://github.com/reactive/data-client/pull/3868" target="_blank" rel="noopener noreferrer" class="">#3868</a> - <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#content"><code>content</code> 文档</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="non-filter-argument-keys">resource() <code>nonFilterArgumentKeys</code><a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#non-filter-argument-keys" class="hash-link" aria-label="non-filter-argument-keys的直接链接" title="non-filter-argument-keys的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#nonFilterArgumentKeys"><code>nonFilterArgumentKeys</code></a> 让 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource">resource()</a>
可以声明哪些参数键<em>不</em>用于过滤集合结果——通常是排序、分页或显示选项。没有它的话，每一组不同的排序或分页参数都会创建一个独立的
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 分桶，新创建的条目也不会出现在使用了不同排序参数的列表中，即便底层数据本应匹配。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> resource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Post</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  group </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  author </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> PostResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:group/posts/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> orderBy</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> author</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  nonFilterArgumentKeys</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'orderBy'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>现在 <code>group</code> 和 <code>author</code> 是过滤键（它们划分出各自独立的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>），而 <code>orderBy</code> 是共享的——<code>PostResource.getList.push()</code> 会把新帖子添加到给定 <code>{ group, author }</code> 分桶的<em>所有</em> <code>orderBy</code> 变体中。</p>
<p>接受 <code>string[]</code>、<code>RegExp</code> 或谓词函数：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">nonFilterArgumentKeys</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token regex regex-delimiter">/</span><span class="token regex regex-source language-regex anchor function" style="color:rgb(130, 170, 255)">^</span><span class="token regex regex-source language-regex group punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token regex regex-source language-regex">orderBy</span><span class="token regex regex-source language-regex alternation keyword" style="font-style:italic">|</span><span class="token regex regex-source language-regex">page</span><span class="token regex regex-source language-regex alternation keyword" style="font-style:italic">|</span><span class="token regex regex-source language-regex">cursor</span><span class="token regex regex-source language-regex group punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token regex regex-source language-regex anchor function" style="color:rgb(130, 170, 255)">$</span><span class="token regex regex-delimiter">/</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><br></div></code></pre></div></div>
<p><a href="https://github.com/reactive/data-client/pull/3914" target="_blank" rel="noopener noreferrer" class="">#3914</a> - <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#nonFilterArgumentKeys"><code>nonFilterArgumentKeys</code> 文档</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="binary-auto-detection">二进制 Content-Type 自动检测<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#binary-auto-detection" class="hash-link" aria-label="二进制 Content-Type 自动检测的直接链接" title="二进制 Content-Type 自动检测的直接链接" translate="no">​</a></h2>
<p>当未设置 <code>content</code> 时，<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#parseResponse"><code>parseResponse</code></a> 现在会自动检测二进制
Content-Type 并返回 <code>response.blob()</code>，而不是通过 <code>.text()</code> 损坏数据。</p>
<p>诸如 <code>image/*</code>、<code>audio/*</code>、<code>video/*</code>、<code>font/*</code>、<code>application/octet-stream</code>、<code>application/pdf</code> 等二进制类型现在都会自动处理。类文本类型（<code>text/*</code>、XML、HTML、JavaScript、CSS 等）继续使用原有的文本 fallback，并附带感知 schema 的错误信息。</p>
<p>这意味着带有正确 Content-Type 头并提供二进制数据的 endpoint 无需任何配置即可工作：</p>
<div class="language-typescript codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-typescript codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/avatars/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Server responds with Content-Type: image/png</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// → automatically returns a Blob (previously corrupted via .text())</span><br></div></code></pre></div></div>
<p><a href="https://github.com/reactive/data-client/pull/3868" target="_blank" rel="noopener noreferrer" class="">#3868</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.18.0 @data-client/rest@^0.18.0 @data-client/endpoint@^0.18.0 @data-client/core@^0.18.0 @data-client/vue@^0.18.0 @data-client/test@^0.18.0 @data-client/img@^0.18.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.18.0 @data-client/rest@^0.18.0 @data-client/endpoint@^0.18.0 @data-client/core@^0.18.0 @data-client/vue@^0.18.0 @data-client/test@^0.18.0 @data-client/img@^0.18.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.18.0 @data-client/rest@^0.18.0 @data-client/endpoint@^0.18.0 @data-client/core@^0.18.0 @data-client/vue@^0.18.0 @data-client/test@^0.18.0 @data-client/img@^0.18.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/endpoint"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/endpoint@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/core"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/core@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/vue"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/vue@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.18.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.18.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<p>本次发布中的破坏性变更仅影响<strong>自定义 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">Schema</a> 实现</strong>。如果你只使用 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource"><code>resource()</code></a> 和内置 schema（<a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity"><code>Entity</code></a>、
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection"><code>Collection</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Union"><code>Union</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Values"><code>Values</code></a>、
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Array"><code>Array</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Object"><code>Object</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Query"><code>Query</code></a>、
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Invalidate"><code>Invalidate</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy"><code>Lazy</code></a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar"><code>Scalar</code></a>），升级可以直接替换完成。</p>
<p>**有自定义 Schema？**如果你使用 AI 智能体，安装迁移 skill 并让它驱动整个流程——codemod、<code>argsKey</code> 注册以及手动清理：</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs tabs_qwsy"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">Skills CLI</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">OpenSkills</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx skills </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> data-client-v0.18-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx openskills </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> reactive/data-client/.agents/skills/data-client-v0.18-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div></div></div>
<p>没有智能体的话，先运行 codemod，再阅读下面各节了解它无法处理的情况（尤其是依赖参数的 schema 所需的 <a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#args-dependent-output" class=""><code>argsKey</code></a>）：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.18.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="denormalize-delegate">Schema.denormalize() 接收 delegate<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#denormalize-delegate" class="hash-link" aria-label="Schema.denormalize() 接收 delegate的直接链接" title="Schema.denormalize() 接收 delegate的直接链接" translate="no">​</a></h3>
<p>如果你没有实现自定义 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">Schema</a> 类，可以跳过本节。</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>Schema.denormalize()</code></a> 现在的签名是 <code>(input, delegate)</code>，取代了以前的 3 参数签名 <code>(input, args, unvisit)</code>。新的
<a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>IDenormalizeDelegate</code></a> 暴露了 <code>unvisit</code>、<code>args</code> 以及新的 <code>argsKey(fn)</code> 辅助方法。
<a href="https://github.com/reactive/data-client/pull/3887" target="_blank" rel="noopener noreferrer" class="">#3887</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Wrapper</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">unvisit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">s</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> v</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IDenormalizeDelegate</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Wrapper</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> IDenormalizeDelegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>codemod 能处理类方法、对象方法、函数声明、TypeScript 接口签名，以及透传式的 <code>someSchema.denormalize(input, args, unvisit)</code> 调用。它还会把
<a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>IDenormalizeDelegate</code></a> 以内联 <code>type</code> 说明符的形式添加到你现有的
<code>@data-client/*</code> 导入中（找不到时则新建一行 <code>import type</code>）。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="args-dependent-output">依赖参数的输出<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#args-dependent-output" class="hash-link" aria-label="依赖参数的输出的直接链接" title="依赖参数的输出的直接链接" translate="no">​</a></h4>
<p>直接读取 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>delegate.args</code></a> <strong>不会</strong>参与记忆化。如果你的 schema 的<em>输出</em>依赖这些参数（例如一个视角），请通过 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>delegate.argsKey(fn)</code></a> 声明这一依赖，以便缓存正确分桶。</p>
<figure class="figure_HN5N"><figcaption class="caption_pMal">codemod 无法推断这个依赖，所以请手动更新这些 schema。</figcaption><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LensSchema</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> lens </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">portfolio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">lookup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> lens</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LensSchema</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> lens </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">lensSelector </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> lens</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ①</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> lens </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">argsKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">lensSelector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ②</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">lookup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> lens</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div><ol class="callouts_q1Zq"><li><span class="marker_TC4U">①</span><span>The function reference is the cache key, so set it once here (or at module scope). An inline arrow would miss the cache on every call.</span></li><li><span class="marker_TC4U">②</span><span><code>argsKey</code> returns <code>fn(args)</code> and records the dependency for memoization.</span></li></ol></figure>
<p>完整示例请参阅 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar">Scalar</a>。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="normalize-delegate">Schema.normalize() 接收 delegate<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#normalize-delegate" class="hash-link" aria-label="Schema.normalize() 接收 delegate的直接链接" title="Schema.normalize() 接收 delegate的直接链接" translate="no">​</a></h3>
<p>如果你没有实现自定义 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">Schema</a> 类，可以跳过本节。</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>Schema.normalize()</code></a> 现在从
<a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>INormalizeDelegate</code></a> 读取 endpoint 参数和递归访问器，与新的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">denormalize delegate</a> 的形式保持一致。以前的签名是 <code>(input, parent, key, args, visit, delegate, parentEntity?)</code>；新的签名是 <code>(input, parent, key, delegate, parentEntity?)</code>。
<a href="https://github.com/reactive/data-client/pull/3934" target="_blank" rel="noopener noreferrer" class="">#3934</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> INormalizeDelegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Visit </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Wrapper</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    visit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Visit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> INormalizeDelegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> normalized </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">visit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mergeEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> normalized</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> normalized</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> INormalizeDelegate </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Wrapper</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> INormalizeDelegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> visit </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> normalized </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">visit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mergeEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> normalized</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> normalized</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>如果你的 schema 接受可选的 <code>parentEntity</code> 参数，请把它保留为最后一个参数：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parentEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>delegate.visit()</code></a> 在递归规范化时已经携带了同样的参数，因此嵌套的
<a class="" href="https://dataclient.io/zh-Hans/rest/api/schema">schema</a> 不需要显式传入参数。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="additive-parententity-on-normalize">新增：normalize 的 <code>parentEntity</code><a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#additive-parententity-on-normalize" class="hash-link" aria-label="additive-parententity-on-normalize的直接链接" title="additive-parententity-on-normalize的直接链接" translate="no">​</a></h4>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple">normalize delegate</a> 的 <code>visit()</code> 回调会在内部跟踪最近的外层类实体 schema，并将其作为可选的末尾参数 <code>parentEntity</code> 转发给 <a class="" href="https://dataclient.io/zh-Hans/rest/api/SchemaSimple"><code>Schema.normalize()</code></a>。新的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema">schema</a> 可以选择利用它，在规范化时发现自己所属的实体（<a class="" href="https://dataclient.io/zh-Hans/rest/api/Scalar">Scalar</a> 在内部就是这样使用的）。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="collection-consolidation">可选：合并 Collection 定义<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#collection-consolidation" class="hash-link" aria-label="可选：合并 Collection 定义的直接链接" title="可选：合并 Collection 定义的直接链接" translate="no">​</a></h4>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection"><code>Collection</code></a> 现在可以在同一个实例上同时使用 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#argsKey"><code>argsKey</code></a> 和
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#nestKey"><code>nestKey</code></a>。作为一项可选的清理，你可以把成对的顶层和嵌套 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 替换为一个共享定义：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getTodos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    todos</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">nestKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> parent </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> parent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userTodos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">//argsKey: params =&gt; ({ ...params }), - this is default, so it's not needed</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">nestKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> parent </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> parent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getTodos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userTodos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    todos</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userTodos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2026/05/01/v0.18-scalar-typed-downloads#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如既往，如果你遇到任何问题或有任何疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>REST</category>
            <category>Schema</category>
            <category>Endpoint</category>
            <category>Collection</category>
        </item>
        <item>
            <title><![CDATA[v0.16：并行获取、Collection.move、Lazy]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy</link>
            <guid>https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy</guid>
            <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[使用 useFetch() 并行加载数据，用 Collection.move 在列表之间重新排列，以及用 Lazy 延迟关系的反规范化]]></description>
            <content:encoded><![CDATA[<p><strong>新特性：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#parallel-data-loading">使用 useFetch() 并行加载数据</a>——通过 <code>use(useFetch())</code> 并发获取多个 endpoint，避免串行瀑布流</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#collection-move">Collection.move</a>——用一次操作在多个 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 之间移动实体</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#collection-move">Collection.moveWith()</a>——自定义移动行为（例如前置插入而非追加）</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#lazy">Lazy</a>——延迟关系的反规范化，以提升性能并隔离记忆化</li>
</ul>
<p><strong>其他改进：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#direct-schema-imports">直接导入 schema</a>——无需 <code>schema</code> 命名空间即可直接导入 schema 类</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#denormalization-depth-limit">反规范化深度限制</a>——防止大型双向实体图导致栈溢出；可通过 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#maxEntityDepth"><code>Entity.maxEntityDepth</code></a> 配置（<a href="https://github.com/reactive/data-client/issues/3822" target="_blank" rel="noopener noreferrer" class="">#3822</a>）</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/DevToolsManager#controllers">DevToolsManager</a> 在开发模式下暴露 <code>globalThis.__DC_CONTROLLERS__</code>，便于从 <a href="https://developer.chrome.com/blog/chrome-devtools-mcp" target="_blank" rel="noopener noreferrer" class="">Chrome DevTools MCP</a> 和 <a href="https://docs.expo.dev/eas/ai/mcp/" target="_blank" rel="noopener noreferrer" class="">Expo MCP</a> 以编程方式访问 store。使用 <a href="https://skills.sh/reactive/data-client/data-client-react" target="_blank" rel="noopener noreferrer" class="">data-client-react skill</a> 来启用 AI 辅助调试。</li>
<li class="">移除 Next.js SSR 期间具有误导性的 'Uncaught Suspense' 警告</li>
<li class="">修复 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint">RestEndpoint</a> 中 <code>method: 'POST'</code> 导致 <code>sideEffect: false</code> 类型丢失的问题</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> 在每个测试之后自动清理——无需手动调用 <code>cleanup()</code></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> 返回每次渲染的 <code>cleanup()</code> 和 <code>allSettled()</code>，让测试的收尾更可靠</li>
</ul>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#move">Collection.move</a> 让你能够用一次操作轻松地在多个 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 之间移动实体：</p>
<div data-playground="true" class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA row_YGZs"><div class="playgroundTextEdit_rt2K withCover_yq1Z"><div class="editorBody_JtfR"><div class="editorDocs_INVk"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">TaskResource</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">TaskCard</div><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">TaskBoard</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-tsx" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useController </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">TaskResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Task</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./TaskResource'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TaskCard</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> task </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> task</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token maybe-class-name">Task</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">handleMove</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token maybe-class-name">TaskResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">move</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">id</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> status</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">status</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'backlog'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'in-progress'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'backlog'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">listItem</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">span</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">style</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> flex</span><span class="token tag script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">1</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">span</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onClick</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">handleMove</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">status</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'backlog'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'\u25bc'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'\u25b2'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">button</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span>
</span></pre></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div></div><div class="storeHost_N0SU"></div><button type="button" class="clean-btn swap_P7aB storeBadge_yrOO" title="显示 Store" aria-pressed="false" data-store-toggle="true"><span aria-hidden="false"><span class="storeBadgeDot_pVWi"></span>Store</span><span aria-hidden="true"><svg class="storeBadgeCode_DfYa" viewBox="0 0 24 24" width="1.15em" height="1.15em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 7-5 5 5 5M16 7l5 5-5 5M14 4l-4 16"></path></svg>代码</span></button></div></div><div class="previewWrapper_edd2"><div class="playgroundHeader_Zx4K previewHeader_MW_M"><span class="liveLabel_MHnJ"><span class="liveLabelText_k6qc">实时预览</span></span><span class="routerSlot_CTii"></span><span class="previewControls_oxCt"><button type="button" class="clean-btn headerButton_h2KM fixturesToggle_OTR0" title="Fixtures" aria-label="Fixtures" aria-expanded="false" aria-controls="_R_85qllq9_"><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 20V4"></path><path d="m3 8 4-4 4 4"></path><path d="M17 4v16"></path><path d="m21 16-4 4-4-4"></path></svg></button><button type="button" class="clean-btn headerButton_h2KM storeHeaderToggle_ToEw" title="显示 Store" aria-label="Store" aria-pressed="false" data-store-toggle="true" disabled=""><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"></ellipse><path d="M4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5"></path><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"></path></svg></button></span></div><div class="fixturesAnchor_fieO"><div id="_R_85qllq9_" class="fixturesPopover_bQwj"><div class="fixtureBlock_mpRK"><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">PATCH</span><span class="fixturePath_Tuwy">/tasks/:id</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ this.tasks[id] || { id, ...body }</span><span class="pill_f9VU fixtureDelay_zwlo">500 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/tasks</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ Object.values(this.tasks).filter(t =&gt; t.status === status)</span><span class="pill_f9VU fixtureDelay_zwlo">150 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div></div></div></div><div class="playgroundResult_tefG"><div class="playgroundPreview_rk9R"></div></div></div></div></div>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#migration-guide">破坏性变更：</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#path-to-regexp-v8">path-to-regexp v8</a>——<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#path">RestEndpoint.path</a> 语法更新：<code>/:optional?</code> → <code>{/:optional}</code>，<code>/:repeat+</code> → <code>/*repeat</code>（类型为 <code>string[]</code>）</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#usefetch-returns-usablepromise">useFetch() 返回 UsablePromise</a>——返回可供 <code>React.use()</code> 使用的 thenable；请检查 <code>.resolved</code> 而不是真值性</li>
</ul>
<p>使用自动化 <a href="https://dataclient.io/zh-Hans/assets/files/v0.16-62bb6d4126ec50f0bac24e3be101bd26.js" target="_blank" class="">codemod</a> 升级，它涵盖所有破坏性变更：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.16.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<!-- -->
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="collection-move">Collection.move<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#collection-move" class="hash-link" aria-label="Collection.move的直接链接" title="Collection.move的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#move">Collection.move</a> 和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#move">RestEndpoint.move</a> 让你能够用一次 PATCH 请求轻松地在多个 collection 之间移动实体。实体会自动从与其旧状态匹配的 collection 中移除，并添加到与请求体中新值匹配的 collection 中。</p>
<p>这对看板、分组重新分配、状态变更，或任何条目需要在筛选列表之间移动的工作流都很有用。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TaskResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/tasks/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  searchParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> status</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Task</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// PATCH /tasks/3 - moves task from 'backlog' to 'in-progress'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  TaskResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">move</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'3'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'3'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> status</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'in-progress'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>同时适用于路径参数和搜索参数，并支持 Array 和 Values collection。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="collectionmovewith">Collection.moveWith()<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#collectionmovewith" class="hash-link" aria-label="Collection.moveWith()的直接链接" title="Collection.moveWith()的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#moveWith">Collection.moveWith()</a> 用于构造自定义的移动 schema，类似于 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#addWith">addWith()</a>。<code>merge</code> 函数控制实体如何被添加到目标 collection（例如前置插入而非追加），而移除行为则会自动推导。为方便使用，还提供了 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#unshift-merge"><code>unshift</code></a> 合并函数。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unshift </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyCollection</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Collection</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">constructor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">super</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> options</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">move </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">moveWith</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">unshift</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="parallel-data-loading">并行加载数据<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#parallel-data-loading" class="hash-link" aria-label="并行加载数据的直接链接" title="并行加载数据的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/useFetch">useFetch()</a> 现在返回一个 <a href="https://react.dev/reference/react/use" target="_blank" rel="noopener noreferrer" class="">UsablePromise</a> thenable，使 <code>use(useFetch(endpoint, args))</code> 成为 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useSuspense">useSuspense()</a> 的即插即用等价物——
数据加载时挂起，已缓存时返回反规范化后的数据，出错时抛出，并在<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#invalidate">失效</a>时重新挂起。</p>
<p>由于 <code>useFetch()</code> 和 <code>use()</code> 是两次独立的调用，多个获取会并行开始。所有 <code>useFetch()</code> 调用都会在任何 <code>use()</code> 挂起之前执行，因此即使第一个 <code>use()</code> 挂起了组件，每个获取也都已经在进行中。这避免了多次调用 <code>useSuspense()</code> 时出现的串行瀑布流，即第二个获取必须等第一个完成后才能开始。
<a href="https://github.com/reactive/data-client/pull/3755" target="_blank" rel="noopener noreferrer" class="">#3755</a></p>
<div data-playground="true" class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA row_YGZs"><div class="playgroundTextEdit_rt2K withCover_yq1Z"><div class="editorBody_JtfR"><div class="editorDocs_INVk"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">Resources</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">PostWithComments</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-tsx" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> use </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useFetch </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">PostResource</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">CommentResource</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./Resources'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">PostWithComments</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Both fetches start in parallel</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> postPromise </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">PostResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> commentsPromise </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">CommentResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> postId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// use() reads the results — if the first suspends,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// the second fetch is already in-flight</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> post </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">postPromise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> comments </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">commentsPromise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">article</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h3</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h4</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">Comments</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h4</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">comments</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">comment </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">key</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">comment</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token tag script language-javascript property-access" style="color:rgb(255, 85, 114)">id</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">listItem</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">          </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">strong</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">comment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">author</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">strong</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">: </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">comment</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">article</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">PostWithComments</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">id</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">1</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div><div class="storeHost_N0SU"></div><button type="button" class="clean-btn swap_P7aB storeBadge_yrOO" title="显示 Store" aria-pressed="false" data-store-toggle="true"><span aria-hidden="false"><span class="storeBadgeDot_pVWi"></span>Store</span><span aria-hidden="true"><svg class="storeBadgeCode_DfYa" viewBox="0 0 24 24" width="1.15em" height="1.15em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 7-5 5 5 5M16 7l5 5-5 5M14 4l-4 16"></path></svg>代码</span></button></div></div><div class="previewWrapper_edd2"><div class="playgroundHeader_Zx4K previewHeader_MW_M"><span class="liveLabel_MHnJ"><span class="liveLabelText_k6qc">实时预览</span></span><span class="routerSlot_CTii"></span><span class="previewControls_oxCt"><button type="button" class="clean-btn headerButton_h2KM fixturesToggle_OTR0" title="Fixtures" aria-label="Fixtures" aria-expanded="false" aria-controls="_R_8mqllq9_"><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 20V4"></path><path d="m3 8 4-4 4 4"></path><path d="M17 4v16"></path><path d="m21 16-4 4-4-4"></path></svg></button><button type="button" class="clean-btn headerButton_h2KM storeHeaderToggle_ToEw" title="显示 Store" aria-label="Store" aria-pressed="false" data-store-toggle="true" disabled=""><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"></ellipse><path d="M4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5"></path><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"></path></svg></button></span></div><div class="fixturesAnchor_fieO"><div id="_R_8mqllq9_" class="fixturesPopover_bQwj"><div class="fixtureBlock_mpRK"><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/posts/1</span><span class="fixtureHint_J1_b" aria-hidden="true">{"id":1,"title":"Parallel Data Loading in React","body":"With useFetch() and React.use(), multiple fetches start at the same time — no sequential waterfalls."}</span><span class="pill_f9VU fixtureDelay_zwlo">600 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/comments?postId=1</span><span class="fixtureHint_J1_b" aria-hidden="true">[{"id":1,"postId":1,"author":"Alice","text":"This pattern is so much faster!"},{"id":2,"postId":1,"author":"Bob","text":"No more request waterfalls 🎉"},{"id":3</span><span class="pill_f9VU fixtureDelay_zwlo">600 ms</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div></div></div></div><div class="playgroundResult_tefG"><div class="playgroundPreview_rk9R"></div></div></div></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="denormalization-depth-limit--lazy">反规范化深度限制与 Lazy<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#denormalization-depth-limit--lazy" class="hash-link" aria-label="反规范化深度限制与 Lazy的直接链接" title="反规范化深度限制与 Lazy的直接链接" translate="no">​</a></h2>
<p>当 schema 在不同实体类型之间存在双向关系时（例如 <code>Department → Building → Department → ...</code>），反规范化会遍历连通图中的每一个唯一实体。数据集较小时这并不明显，但在大规模下——成千上万个相互关联的实体——递归会超出 JS 调用栈并抛出
<code>RangeError: Maximum call stack size exceeded</code>。
<a href="https://github.com/reactive/data-client/issues/3822" target="_blank" rel="noopener noreferrer" class="">#3822</a></p>
<p>两个互补的特性解决了这个问题：作为安全网的<strong>深度限制</strong>，以及
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy"><strong>Lazy</strong></a>，用于按字段精确控制哪些关系被急切解析。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="denormalization-depth-limit">反规范化深度限制<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#denormalization-depth-limit" class="hash-link" aria-label="反规范化深度限制的直接链接" title="反规范化深度限制的直接链接" translate="no">​</a></h3>
<p>反规范化现在默认强制执行 64 层实体跳转的深度限制。超出限制的实体会以未解析的 id 返回，而不是完全反规范化后的对象。在开发模式下达到该限制时会输出一条 <code>console.error</code>。</p>
<p>可以通过 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#maxEntityDepth"><code>static maxEntityDepth</code></a> 为每个 Entity 单独配置该限制：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Department</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> maxEntityDepth </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">16</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>这可以防止崩溃，但它是一把钝刀——会切断<em>所有</em>深层路径，包括合法的非循环路径。若需要细粒度控制，请使用 <a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#lazy" class="">Lazy</a>。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="lazy">Lazy<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#lazy" class="hash-link" aria-label="Lazy的直接链接" title="Lazy的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy">Lazy</a> 包装一个 schema，以跳过对特定关系字段的急切反规范化。在父实体反规范化期间，该字段保留其原始的规范化值（主键）。之后可以通过 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery">useQuery</a> 使用 <code>.query</code> 访问器按需解析该关系。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Lazy </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Department</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  buildings</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    buildings</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Lazy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Building</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>与深度限制不同，<code>Lazy</code> 是针对单个关系的、有针对性的选择性启用。只有你标记为 lazy 的字段会跳过急切解析——schema 的其余部分照常反规范化。这也通过推迟那些并非总是需要的关系的处理工作来提升性能，并提供了<strong>记忆化隔离</strong>——
lazy 实体的变化不会让父实体的反规范化结果失效。</p>
<p>完整用法请参阅 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy">Lazy 文档</a>，设计讨论请参阅
<a href="https://github.com/reactive/data-client/discussions/3828" target="_blank" rel="noopener noreferrer" class="">#3828</a>。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.16.0 @data-client/rest@^0.16.0 @data-client/endpoint@^0.16.0 @data-client/core@^0.16.0 @data-client/vue@^0.16.0 @data-client/test@^0.16.0 @data-client/img@^0.16.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.16.0 @data-client/rest@^0.16.0 @data-client/endpoint@^0.16.0 @data-client/core@^0.16.0 @data-client/vue@^0.16.0 @data-client/test@^0.16.0 @data-client/img@^0.16.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.16.0 @data-client/rest@^0.16.0 @data-client/endpoint@^0.16.0 @data-client/core@^0.16.0 @data-client/vue@^0.16.0 @data-client/test@^0.16.0 @data-client/img@^0.16.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/endpoint"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/endpoint@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/core"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/core@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/vue"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/vue@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.16.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.16.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<p>自动化 <a href="https://dataclient.io/zh-Hans/assets/files/v0.16-62bb6d4126ec50f0bac24e3be101bd26.js" target="_blank" class="">codemod</a> 可以处理下面全部三项破坏性变更——路径语法、<code>useFetch()</code> 真值性检查，以及 <code>schema</code> 命名空间导入：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.16.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="path-to-regexp-v8">path-to-regexp v8<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#path-to-regexp-v8" class="hash-link" aria-label="path-to-regexp v8的直接链接" title="path-to-regexp v8的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#path">RestEndpoint.path</a> 现在使用 <a href="https://github.com/pillarjs/path-to-regexp/releases/tag/v8.0.0" target="_blank" rel="noopener noreferrer" class="">path-to-regexp v8</a>，它改变了可选参数、重复参数和特殊字符的语法。</p>
<div class="table-scroll"><table><thead><tr><th>v6 语法</th><th>v8 语法</th><th>说明</th></tr></thead><tbody><tr><td><code>/:optional?</code></td><td><code>{/:optional}</code></td><td>可选参数</td></tr><tr><td><code>/:repeat+</code></td><td><code>/*repeat</code></td><td>重复一次或多次（类型为 <code>string[]</code>）</td></tr><tr><td><code>/:repeat*</code></td><td><code>{/*repeat}</code></td><td>重复零次或多次（类型为 <code>string[]</code>）</td></tr><tr><td><code>/:with-dash</code></td><td><code>/:"with-dash"</code></td><td>带引号的参数名</td></tr><tr><td><code>/:id(\d+)</code></td><td><code>/:id</code></td><td>移除自定义正则</td></tr></tbody></table></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="optional-parameters">可选参数<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#optional-parameters" class="hash-link" aria-label="可选参数的直接链接" title="可选参数的直接链接" translate="no">​</a></h3>
<p><code>?</code> 后缀已移除。请把可选片段（包括其前缀）包在 <code>{}</code> 中。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:group/things/:number?'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:group/things{/:number}'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>带有不同前缀的多个可选片段：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:attr1?{-:attr2}?{-:attr3}?'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{/:attr1}{-:attr2}{-:attr3}'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="repeating-parameters">重复参数<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#repeating-parameters" class="hash-link" aria-label="重复参数的直接链接" title="重复参数的直接链接" translate="no">​</a></h3>
<p><code>+</code>（一次或多次）和 <code>*</code>（零次或多次）后缀已移除。请使用 <code>*name</code> 通配符语法，零次或多次的情况需包在 <code>{}</code> 中。</p>
<p>通配符参数的类型现在是 <code>string[]</code>（数组）而不是 <code>string | number</code>，因为它们表示多个路径片段。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/files/:path+'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">ep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'docs/reports/q4'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> optEp </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/files/:path*'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/files/*path'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">ep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'docs'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'reports'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'q4'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> optEp </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/files{/*path}'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="quoted-parameter-names">带引号的参数名<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#quoted-parameter-names" class="hash-link" aria-label="带引号的参数名的直接链接" title="带引号的参数名的直接链接" translate="no">​</a></h3>
<p>包含特殊字符（连字符、点）的参数名现在必须用双引号括起来：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:with-dash'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:"with-dash"'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="custom-regex-removed">移除自定义正则<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#custom-regex-removed" class="hash-link" aria-label="移除自定义正则的直接链接" title="移除自定义正则的直接链接" translate="no">​</a></h3>
<p>不再支持像 <code>/:id(\d+)</code> 这样的内联正则模式。请移除正则——改为在服务端进行校验。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id(\\d+)'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="escaping-special-characters">转义特殊字符<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#escaping-special-characters" class="hash-link" aria-label="转义特殊字符的直接链接" title="转义特殊字符的直接链接" translate="no">​</a></h3>
<p>包括 <code>{}()[]+?!:*\\</code> 在内的字符在路径模式中作为<strong>字面量</strong>使用时，必须用 <code>\\</code> 转义。这些字符<a href="https://github.com/pillarjs/path-to-regexp#express--4x" target="_blank" rel="noopener noreferrer" class="">被 path-to-regexp 保留</a>，未转义地使用会抛出 <a href="https://github.com/pillarjs/path-to-regexp#unexpected--or-" target="_blank" rel="noopener noreferrer" class="">Unexpected token 错误</a>。模式中的字面量查询字符串仍然需要转义 <code>?</code>，例如 <code>'/resource\\?per_page=50'</code>。</p>
<p>当查询片段使用<strong>命名参数</strong>时，优先使用显式分组而不是单个转义的 <code>?</code>：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/search\\?q=:q'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ep </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/search?{q=:q}{&amp;page=:page}'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="finding-paths-to-migrate">查找需要迁移的路径<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#finding-paths-to-migrate" class="hash-link" aria-label="查找需要迁移的路径的直接链接" title="查找需要迁移的路径的直接链接" translate="no">​</a></h3>
<p>在代码库的 <code>path:</code> 值中搜索以下模式：</p>
<ul>
<li class=""><code>:param</code> 之后的 <strong><code>?</code></strong>——需要转换的可选参数</li>
<li class=""><code>:param</code> 之后的 <strong><code>+</code></strong> 或 <strong><code>*</code></strong>——需要转换的重复参数</li>
<li class=""><code>:param</code> 之后的 <strong><code>(\</code></strong>——需要移除的自定义正则</li>
<li class="">包含 <strong><code>-</code></strong> 或 <strong><code>.</code></strong> 的参数名——需要加引号</li>
</ul>
<p>完整的 v8 语法文档请参阅 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#path">RestEndpoint.path</a>，详细解释请参阅 <a href="https://github.com/pillarjs/path-to-regexp#errors" target="_blank" rel="noopener noreferrer" class="">path-to-regexp 错误说明</a>。也可以使用 AI 辅助迁移：</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs tabs_qwsy"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">Skills CLI</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">OpenSkills</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx skills </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> reactive/data-client </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--skill</span><span class="token plain"> path-to-regexp-v8-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx openskills </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> reactive/data-client/.agents/skills/path-to-regexp-v8-migration</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="usefetch-returns-usablepromise">useFetch() 返回 UsablePromise<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#usefetch-returns-usablepromise" class="hash-link" aria-label="useFetch() 返回 UsablePromise的直接链接" title="useFetch() 返回 UsablePromise的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/useFetch">useFetch()</a> 现在返回一个 <code>UsablePromise</code> thenable，带有反规范化后的数据、错误处理和 <code>.resolved</code> 属性。这使它可以直接与 <a href="https://react.dev/reference/react/use" target="_blank" rel="noopener noreferrer" class="">React.use()</a> 配合使用——<code>use(useFetch(endpoint, args))</code> 的行为与 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useSuspense">useSuspense()</a> 完全相同。</p>
<p>之前，当数据有效时 <code>useFetch()</code> 返回 <code>undefined</code>。通过真值性来判断是否发起了获取的代码，现在必须改用 <code>.resolved</code>：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> promise </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">PostResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">promise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// fetch was triggered</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> promise </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">PostResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">promise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">resolved</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// fetch is in-flight</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">promise</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// suspends or returns denormalized data</span><br></div></code></pre></div></div></div></figure>
<p>关于这如何实现并发获取、避免串行瀑布流，请参阅上文的<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#parallel-data-loading" class="">并行加载数据</a>。
<a href="https://github.com/reactive/data-client/pull/3752" target="_blank" rel="noopener noreferrer" class="">#3752</a>、<a href="https://github.com/reactive/data-client/pull/3755" target="_blank" rel="noopener noreferrer" class="">#3755</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="direct-schema-imports">直接导入 schema<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#direct-schema-imports" class="hash-link" aria-label="直接导入 schema的直接链接" title="直接导入 schema的直接链接" translate="no">​</a></h2>
<p>Schema 类现在可以直接从 <a href="https://www.npmjs.com/package/@data-client/endpoint" target="_blank" rel="noopener noreferrer" class="">@data-client/endpoint</a>（或重新导出它们的 <a href="https://www.npmjs.com/package/@data-client/rest" target="_blank" rel="noopener noreferrer" class="">@data-client/rest</a>）导入，而无需通过 <code>schema</code> 命名空间。这提供了更简洁的导入语法，同时保持完全的向后兼容。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> schema </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/endpoint'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> myUnion </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Union</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> users</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> groups</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Group </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token string" style="color:rgb(195, 232, 141)">'type'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Union </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/endpoint'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> myUnion </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Union</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> users</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> groups</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Group </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token string" style="color:rgb(195, 232, 141)">'type'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>所有 schema 类都可以直接导入：<a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Invalidate">Invalidate</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Values">Values</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/All">All</a> 和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Lazy">Lazy</a>。为了向后兼容，<code>schema</code> 命名空间导出仍然可用。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2026/04/01/v0.16-parallel-fetching-collection-move-lazy#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如往常，如果你遇到任何问题或有疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>REST</category>
            <category>Schema</category>
            <category>Collection</category>
        </item>
        <item>
            <title><![CDATA[v0.15：Vue 3、Collection.remove、useDebounce 升级]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove</link>
            <guid>https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove</guid>
            <pubDate>Tue, 06 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Vue 3 组合式函数、用于高效管理列表的 Collection.remove、改进的 Union 查询，以及性能提升]]></description>
            <content:encoded><![CDATA[<p><strong>新平台：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#vue-3-support">Vue 3</a>，提供完整的组合式函数：useSuspense、useCache、useDLE、useController、useQuery</li>
</ul>
<p><strong>新特性：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#collectionremove">Collection.remove</a>，用于从集合中移除条目</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#restendpointremove">RestEndpoint.remove</a>，将 PATCH 与集合移除合二为一</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#union-queries">Union 无需类型判别字段即可 query()</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#invalidate-unions">Invalidate 支持 Union</a>，用于多态删除操作</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#mockinitialstate">mockInitialState()</a>，让测试搭建更简单</li>
</ul>
<p><strong>性能：</strong></p>
<ul>
<li class="">get/denormalize 操作<a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#performance">提升 10-20%</a></li>
</ul>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#migration-guide">破坏性变更：</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#usedebounce">useDebounce() 返回 [val, isPending]</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#immutablejs">ImmutableJS 支持移至 /imm 导出</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#schema-delegate">Schema delegate 接口整合</a></li>
</ul>
<p>使用自动化 <a href="https://dataclient.io/zh-Hans/assets/files/v0.15-a09ab84c5309f63d14af1950930d3ba3.js" target="_blank" class="">codemod</a> 完成常见破坏性变更的升级：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.15.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<!-- -->
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="vue-3-support">Vue 3 支持<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#vue-3-support" class="hash-link" aria-label="Vue 3 支持的直接链接" title="Vue 3 支持的直接链接" translate="no">​</a></h2>
<p>全新的 <a href="https://www.npmjs.com/package/@data-client/vue" target="_blank" rel="noopener noreferrer" class=""><code>@data-client/vue</code></a> 包以原生组合式函数的形式，将 Reactive Data Client 的全部能力带到了 Vue 3。<a href="https://github.com/reactive/data-client/pull/3549" target="_blank" rel="noopener noreferrer" class="">#3549</a>、<a href="https://github.com/reactive/data-client/pull/3585" target="_blank" rel="noopener noreferrer" class="">#3585</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="installation">安装<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#installation" class="hash-link" aria-label="安装的直接链接" title="安装的直接链接" translate="no">​</a></h3>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> @data-client/vue @data-client/rest</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="setup">设置<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#setup" class="hash-link" aria-label="设置的直接链接" title="设置的直接链接" translate="no">​</a></h3>
<p>在你的应用上安装 <a class="" href="https://dataclient.io/zh-Hans/vue/api/DataClientPlugin">DataClientPlugin</a>：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">main.ts</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createApp </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> DataClientPlugin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createApp</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'#app'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="composables">组合式函数<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#composables" class="hash-link" aria-label="组合式函数的直接链接" title="组合式函数的直接链接" translate="no">​</a></h3>
<p>所有你熟悉的 hook 都以 Vue 组合式函数的形式提供：</p>
<div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">ArticleDetail.vue</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">setup</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">lang</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">ts</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript keyword module" style="font-style:italic">import</span><span class="token script language-javascript"> </span><span class="token script language-javascript imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript imports"> useSuspense </span><span class="token script language-javascript imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"> </span><span class="token script language-javascript keyword module" style="font-style:italic">from</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript keyword module" style="font-style:italic">import</span><span class="token script language-javascript"> </span><span class="token script language-javascript imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript imports"> </span><span class="token script language-javascript imports maybe-class-name">ArticleResource</span><span class="token script language-javascript imports"> </span><span class="token script language-javascript imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"> </span><span class="token script language-javascript keyword module" style="font-style:italic">from</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">'./resources'</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript keyword" style="font-style:italic">const</span><span class="token script language-javascript"> props </span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">=</span><span class="token script language-javascript"> defineProps</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"> </span><span class="token script language-javascript literal-property property">id</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> string </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript keyword" style="font-style:italic">const</span><span class="token script language-javascript"> article </span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">=</span><span class="token script language-javascript"> </span><span class="token script language-javascript keyword control-flow" style="font-style:italic">await</span><span class="token script language-javascript"> </span><span class="token script language-javascript function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript maybe-class-name">ArticleResource</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript property-access">get</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript function" style="color:rgb(130, 170, 255)">computed</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"> </span><span class="token script language-javascript literal-property property">id</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> props</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token script language-javascript property-access">id</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">template</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">article</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">h1</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">{{ article.title }}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">h1</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain">{{ article.content }}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">p</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">article</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">template</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<p>可用的组合式函数：</p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/vue/api/useSuspense"><code>useSuspense()</code></a> - 支持 Suspense 的数据获取</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/vue/api/useCache"><code>useCache()</code></a> - 从缓存读取而不发起获取</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/vue/api/useDLE"><code>useDLE()</code></a> - 不使用 Suspense 的数据/加载/错误模式 <a href="https://github.com/reactive/data-client/pull/3592" target="_blank" rel="noopener noreferrer" class="">#3592</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/vue/api/useController"><code>useController()</code></a> - 访问 controller 以执行变更</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/vue/api/useQuery"><code>useQuery()</code></a> - 直接查询 schema</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="testing-with-mockplugin">使用 MockPlugin 进行测试<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#testing-with-mockplugin" class="hash-link" aria-label="使用 MockPlugin 进行测试的直接链接" title="使用 MockPlugin 进行测试的直接链接" translate="no">​</a></h3>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">test setup</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createApp </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> DataClientPlugin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> MockPlugin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/vue/test'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createApp</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">App</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">DataClientPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">use</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">MockPlugin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  fixtures</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      endpoint</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> MyResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      response</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> name</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Test'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div style="text-align:center"><a class="button button--primary" href="https://dataclient.io/zh-Hans/vue/getting-started/agent-skills">快速上手指南</a></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="collectionremove">Collection.remove<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#collectionremove" class="hash-link" aria-label="Collection.remove的直接链接" title="Collection.remove的直接链接" translate="no">​</a></h2>
<p>新的 schema，用于在不删除实体本身的情况下从 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 中移除条目。<a href="https://github.com/reactive/data-client/pull/3560" target="_blank" rel="noopener noreferrer" class="">#3560</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> schema </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoCollection </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getList</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> TodoCollection </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Remove from collection without deleting</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'123'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>当某个条目应从列表视图中移除、但仍需存在于其他地方时，这非常有用：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Remove user from a specific group list</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">UserResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'admins'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="restendpointremove">RestEndpoint.remove<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#restendpointremove" class="hash-link" aria-label="RestEndpoint.remove的直接链接" title="RestEndpoint.remove的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#remove">RestEndpoint.remove</a> 将 PATCH 更新与集合移除结合在一起——非常适合“归档”或“移动”操作。<a href="https://github.com/reactive/data-client/pull/3623" target="_blank" rel="noopener noreferrer" class="">#3623</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getTodos </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Removes Todo from collection AND updates it with new data</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getTodos</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'123'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Done'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> archived</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Move user between groups</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  UserResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'team-a'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'team-b'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// User removed from 'team-a' list AND entity updated with group: 'team-b'</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="union-queries">Union 查询<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#union-queries" class="hash-link" aria-label="Union 查询的直接链接" title="Union 查询的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a> 现在无需指定类型判别字段即可查询。<a href="https://github.com/reactive/data-client/pull/3558" target="_blank" rel="noopener noreferrer" class="">#3558</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Type discriminator required</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// @ts-expect-error - missing 'type'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> event </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">EventUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// event is undefined</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> newsEvent </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">EventUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> type</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'news'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// newsEvent is found</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Works without type discriminator</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> event </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">EventUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// event is found!</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> newsEvent </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">EventUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> type</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'news'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// newsEvent is also found</span><br></div></code></pre></div></div></div></figure>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="invalidate-unions">Invalidate 支持 Union<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#invalidate-unions" class="hash-link" aria-label="Invalidate 支持 Union的直接链接" title="Invalidate 支持 Union的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Invalidate">schema.Invalidate</a> 现在接受 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a> schema，用于多态删除操作。此外，<a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#delete">resource().delete</a> 会自动用 Invalidate 包装 Union schema。<a href="https://github.com/reactive/data-client/pull/3559" target="_blank" rel="noopener noreferrer" class="">#3559</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> FeedUnion </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Union</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> posts</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> comments</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Comment </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token string" style="color:rgb(195, 232, 141)">'type'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// resource() automatically handles Union delete</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> FeedResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/feed/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> FeedUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">FeedResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">delete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'123'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// For standalone endpoints, use schema.Invalidate directly</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> deleteFeedItem </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/feed/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  method</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'DELETE'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Invalidate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">FeedUnion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">deleteFeedItem</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'123'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="testing-utilities">测试工具<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#testing-utilities" class="hash-link" aria-label="测试工具的直接链接" title="测试工具的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="mockinitialstate">mockInitialState()<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#mockinitialstate" class="hash-link" aria-label="mockInitialState()的直接链接" title="mockInitialState()的直接链接" translate="no">​</a></h3>
<p>用于在测试中创建预填充状态的新工具。<a href="https://github.com/reactive/data-client/commit/a4092a1499" target="_blank" rel="noopener noreferrer" class=""><code>a4092a1</code></a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> mockInitialState </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/mock'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> ArticleResource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./resources'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> state </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">mockInitialState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    endpoint</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    response</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Hello'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> content</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'World'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="data-clientcoremock">@data-client/core/mock<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#data-clientcoremock" class="hash-link" aria-label="@data-client/core/mock的直接链接" title="@data-client/core/mock的直接链接" translate="no">​</a></h3>
<p>新的 mock 入口，提供用于构建自定义 mock 实现的工具：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  MockController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  collapseFixture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  createFixtureMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/core/mock'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>MockController</code> - 用于 mock endpoint 的 Controller 包装器</li>
<li class=""><code>collapseFixture</code> - 解析 fixture 响应（处理函数形式的响应）</li>
<li class=""><code>createFixtureMap</code> - 将 fixture 拆分为静态映射和 interceptor</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="performance">性能<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#performance" class="hash-link" aria-label="性能的直接链接" title="性能的直接链接" translate="no">​</a></h2>
<p>移除 ImmutableJS 自动检测开销并优化反规范化代码路径，为 get/denormalize 操作带来了 <strong>10-20% 的提升</strong>。<a href="https://github.com/reactive/data-client/pull/3421" target="_blank" rel="noopener noreferrer" class="">#3421</a>、<a href="https://github.com/reactive/data-client/pull/3468" target="_blank" rel="noopener noreferrer" class="">#3468</a></p>
<center><div style="max-width:500px"></div><p><a href="https://reactive.github.io/data-client/dev/bench/" target="_blank" rel="noopener noreferrer" class="">历史基准测试</a> | <a href="https://github.com/reactive/data-client/tree/master/examples/benchmark" target="_blank" rel="noopener noreferrer" class="">查看基准测试</a></p></center>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-improvements">其他改进<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#other-improvements" class="hash-link" aria-label="其他改进的直接链接" title="其他改进的直接链接" translate="no">​</a></h2>
<ul>
<li class="">修复 paginationField 位于 body 中时 <code>getPage</code> 的类型</li>
<li class="">修复 <a class="" href="https://dataclient.io/zh-Hans/rest/api/All">schema.All()</a> 对已失效实体的多态处理</li>
<li class="">修复 <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#get">controller.get</a> 和 controller.getQueryMeta 的 'state' 参数类型</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<!-- -->
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.15.0 @data-client/rest@^0.15.0 @data-client/test@^0.15.0 @data-client/img@^0.15.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.15.0 @data-client/rest@^0.15.0 @data-client/test@^0.15.0 @data-client/img@^0.15.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.15.0 @data-client/rest@^0.15.0 @data-client/test@^0.15.0 @data-client/img@^0.15.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.15.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.15.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.15.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.15.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<p>自动化 <a href="https://dataclient.io/zh-Hans/assets/files/v0.15-a09ab84c5309f63d14af1950930d3ba3.js" target="_blank" class="">codemod</a> 可以处理下面这些破坏性变更：</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token plain">npx jscodeshift </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-t</span><span class="token plain"> https://dataclient.io/codemods/v0.15.js </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--extensions</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ts,tsx,js,jsx src/</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="usedebounce">useDebounce() 返回 [val, isPending]<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#usedebounce" class="hash-link" aria-label="useDebounce() 返回 [val, isPending]的直接链接" title="useDebounce() 返回 [val, isPending]的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/useDebounce">useDebounce()</a> 现在返回一个包含 pending 状态的元组，与 React 19 的 <code>useTransition</code> 模式保持一致。<a href="https://github.com/reactive/data-client/pull/3459" target="_blank" rel="noopener noreferrer" class="">#3459</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useDebounce </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> debouncedQuery </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useDebounce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">100</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useDebounce </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">debouncedQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useDebounce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">100</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Or use the pending state</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">debouncedQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> isPending</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useDebounce</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">100</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<div class="theme-admonition theme-admonition-tip admonition_WCGJ alert alert--success"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_pbrs"><p>旧的签名仍可通过 <code>@data-client/react/next</code> 使用，以便逐步迁移。</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="immutablejs">ImmutableJS 移至 /imm 导出<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#immutablejs" class="hash-link" aria-label="ImmutableJS 移至 /imm 导出的直接链接" title="ImmutableJS 移至 /imm 导出的直接链接" translate="no">​</a></h3>
<p>ImmutableJS 支持不再自动检测。请使用显式的 <code>/imm</code> 导出来处理 ImmutableJS 状态。<a href="https://github.com/reactive/data-client/pull/3421" target="_blank" rel="noopener noreferrer" class="">#3421</a>、<a href="https://github.com/reactive/data-client/pull/3468" target="_blank" rel="noopener noreferrer" class="">#3468</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> MemoCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> denormalize </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/normalizr'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> memo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MemoCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Auto-detected ImmutableJS</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> MemoCache </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/normalizr'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> MemoPolicy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> normalize </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/normalizr/imm'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> memo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MemoCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">MemoPolicy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p><code>/imm</code> 入口现在同时包含 <code>normalize()</code> 和 <code>denormalize()</code>，以完整支持 ImmutableJS 状态处理：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> normalize </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/normalizr/imm'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> fromJS </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'immutable'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Article</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> responseData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  entities</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fromJS</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  indexes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fromJS</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  entitiesMeta</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">fromJS</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// result.entities is an ImmutableJS Map</span><br></div></code></pre></div></div>
<p>这一变化为不使用 ImmutableJS 的用户移除了 ImmutableJS 检测开销，带来 10-20% 的性能提升。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schema-delegate">Schema delegate 接口变更<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#schema-delegate" class="hash-link" aria-label="Schema delegate 接口变更的直接链接" title="Schema delegate 接口变更的直接链接" translate="no">​</a></h3>
<p>如果你有重写了 <code>normalize()</code> 或 <code>queryKey()</code> 的自定义 schema，这些回调参数已被整合为一个 <code>delegate</code> 对象。<a href="https://github.com/reactive/data-client/pull/3449" target="_blank" rel="noopener noreferrer" class="">#3449</a></p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="normalize">normalize()<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#normalize" class="hash-link" aria-label="normalize()的直接链接" title="normalize()的直接链接" translate="no">​</a></h4>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">visit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  addEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  checkLoop</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">addEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">visit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> INormalizeDelegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mergeEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="querykey">queryKey()<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#querykey" class="hash-link" aria-label="queryKey()的直接链接" title="queryKey()的直接链接" translate="no">​</a></h4>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> indexName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> indexName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="delegategetentity--delegategetentities-3501">delegate.getEntity → delegate.getEntities <a href="https://github.com/reactive/data-client/pull/3501" target="_blank" rel="noopener noreferrer" class="">#3501</a><a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#delegategetentity--delegategetentities-3501" class="hash-link" aria-label="delegategetentity--delegategetentities-3501的直接链接" title="delegategetentity--delegategetentities-3501的直接链接" translate="no">​</a></h4>
<p>遍历某一类型的全部实体时，请使用 <code>delegate.getEntities()</code>，它返回一个受限接口，提供 <code>keys()</code> 和 <code>entries()</code> 迭代器方法：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> entities </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  Object</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">keys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">forEach</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">collectionPk </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">filterCollections</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">collectionPk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mergeEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> collectionPk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> normalizedValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> entities </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getEntities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> collectionKey </span><span class="token keyword" style="font-style:italic">of</span><span class="token plain"> entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">keys</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">filterCollections</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">parse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">collectionKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">continue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">mergeEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> collectionKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> normalizedValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="invalid-removed">移除 INVALID 符号<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#invalid-removed" class="hash-link" aria-label="移除 INVALID 符号的直接链接" title="移除 INVALID 符号的直接链接" translate="no">​</a></h3>
<p><code>INVALID</code> 符号不再导出。请改用 delegate 的方法。<a href="https://github.com/reactive/data-client/pull/3461" target="_blank" rel="noopener noreferrer" class="">#3461</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">INVALID</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/endpoint'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">setEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">INVALID</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">found</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">INVALID</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">invalidate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unvisit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">found</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> delegate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">INVALID</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="entitiesmeta">state.entityMeta -&gt; state.entitiesMeta<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#entitiesmeta" class="hash-link" aria-label="state.entityMeta -> state.entitiesMeta的直接链接" title="state.entityMeta -> state.entitiesMeta的直接链接" translate="no">​</a></h3>
<p>为保持一致性而重命名的内部状态属性。这只影响直接访问 store 的代码。<a href="https://github.com/reactive/data-client/pull/3451" target="_blank" rel="noopener noreferrer" class="">#3451</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="networkmanager">NetworkManager 数据结构变更<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#networkmanager" class="hash-link" aria-label="NetworkManager 数据结构变更的直接链接" title="NetworkManager 数据结构变更的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/NetworkManager">NetworkManager</a> 的 <code>fetched</code>、<code>rejectors</code>、<code>resolvers</code>、<code>fetchedAt</code>
已被整合为 <code>fetching</code>。<a href="https://github.com/reactive/data-client/pull/3394" target="_blank" rel="noopener noreferrer" class="">#3394</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key </span><span class="token keyword" style="font-style:italic">in</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fetched</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">fetching</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">has</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="memocache">MemoCache API 变更（normalizr）<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#memocache" class="hash-link" aria-label="MemoCache API 变更（normalizr）的直接链接" title="MemoCache API 变更（normalizr）的直接链接" translate="no">​</a></h3>
<p>面向直接使用 <a href="https://www.npmjs.com/package/@data-client/normalizr" target="_blank" rel="noopener noreferrer" class="">@data-client/normalizr</a> 的用户：</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="memocachequery-and-buildquerykey-take-state-as-one-argument-3372">MemoCache.query() 和 buildQueryKey() 以单个参数接收 state <a href="https://github.com/reactive/data-client/pull/3372" target="_blank" rel="noopener noreferrer" class="">#3372</a><a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#memocachequery-and-buildquerykey-take-state-as-one-argument-3372" class="hash-link" aria-label="memocachequery-and-buildquerykey-take-state-as-one-argument-3372的直接链接" title="memocachequery-and-buildquerykey-take-state-as-one-argument-3372的直接链接" translate="no">​</a></h4>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">buildQueryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">indexes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">indexes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">buildQueryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="memocachequery-returns--data-paths-">MemoCache.query() 返回 { data, paths }<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#memocachequery-returns--data-paths-" class="hash-link" aria-label="MemoCache.query() 返回 { data, paths }的直接链接" title="MemoCache.query() 返回 { data, paths }的直接链接" translate="no">​</a></h4>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">typeof</span><span class="token plain"> data </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'symbol'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">data </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2026/01/06/v0.15-vue-support-collection-remove#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如既往，如果你遇到任何问题或有任何疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>Vue</category>
            <category>Schema</category>
        </item>
        <item>
            <title><![CDATA[v0.14：精简的 Manager API、性能提升与 GC]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement</link>
            <guid>https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement</guid>
            <pubDate>Sat, 13 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[更快的获取、缩小 30% 的包体积、自动垃圾回收，以及更简洁的 Manager API]]></description>
            <content:encoded><![CDATA[<p><strong>Manager：</strong></p>
<p>Manager API 得到了精简——更扁平的 action 结构降低了代码复杂度，并通过减少不同的内联缓存条目来提升性能；同时更简单的配置 API 让自定义更加愉快。</p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-shapes">简化的 action 结构</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#manager-middleware">Manager.middleware</a> 属性</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#getdefaultmanagers">getDefaultManagers()</a> 配置</li>
</ul>
<p><strong>性能：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#immediate-fetching">立即发起 fetch 调用</a>——不再等待空闲</li>
<li class="">通过移除不必要的 polyfill，<a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#bundle-size">包体积缩小 30%</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#normalization-performance">规范化快 10%，反规范化快 32%</a></li>
</ul>
<p><strong>Schema/数据建模：</strong></p>
<ul>
<li class="">使用 Object Schema 进行 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#query-joins">Query 连接</a></li>
<li class="">用于组合 Entity 行为的 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#entitymixin">EntityMixin</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#entity-pk-default">Entity.pk() 默认值</a>使用 <code>id</code></li>
<li class="">通过 Entity.process() 实现<a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#dynamic-invalidation">动态失效</a></li>
</ul>
<p><strong>测试：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#renderdatahook">renderDataHook()</a> 让测试更简单</li>
</ul>
<p><strong>垃圾回收：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#gcpolicy">GCPolicy</a>——自动回收过时数据</li>
</ul>
<p><strong><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#migration-guide">破坏性变更：</a></strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#networkmanager">NetworkManager 立即发起获取</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-response">action.payload -&gt; action.response</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-args">action.meta.args -&gt; action.args</a></li>
</ul>
<!-- -->
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="managers">Manager<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#managers" class="hash-link" aria-label="Manager的直接链接" title="Manager的直接链接" translate="no">​</a></h2>
<p>Manager API 得到了精简——更扁平的 action 结构降低了代码复杂度，并通过减少不同的内联缓存条目来提升性能；同时更简单的配置 API 让自定义更加愉快。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="action-shapes">Action 结构<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-shapes" class="hash-link" aria-label="Action 结构的直接链接" title="Action 结构的直接链接" translate="no">​</a></h3>
<p>Action 结构更简单、更一致。<a href="https://github.com/reactive/data-client/pull/3143" target="_blank" rel="noopener noreferrer" class="">#3143</a>、<a href="https://github.com/reactive/data-client/pull/3139" target="_blank" rel="noopener noreferrer" class="">#3139</a></p>
<ul>
<li class=""><code>action.meta.args</code> -&gt; <code>action.args</code></li>
<li class=""><code>action.meta.key</code> -&gt; <code>action.key</code></li>
<li class=""><code>action.meta.nm</code> 已移除（未使用）</li>
<li class=""><code>action.payload</code> -&gt; <code>action.response</code>（针对 SET_RESPONSE）</li>
</ul>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"type"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"rdc/setresponse"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"meta"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"key"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"PATCH https://jsonplaceholder.typicode.com/todos/1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"payload"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"userId"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"delectus aut autem"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"completed"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token property">"completed"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"nm"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"endpoint"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Todo.partialUpdate"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"schema"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"key"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Todo"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"schema"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"sideEffect"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"fetchedAt"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"12:44:24.206 PM"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"date"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"12:44:24.334 PM"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"expiresAt"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1:44:24.334 PM"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"error"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"type"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"rdc/setresponse"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"key"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"PATCH https://jsonplaceholder.typicode.com/todos/1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"response"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"userId"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"delectus aut autem"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"completed"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"args"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token property">"completed"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"endpoint"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Todo.partialUpdate"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"schema"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"key"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Todo"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"schema"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"sideEffect"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"meta"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"fetchedAt"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"12:44:24.206 PM"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"date"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"12:44:24.334 PM"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"expiresAt"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1:44:24.334 PM"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"error"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="manager-middleware">Manager.middleware<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#manager-middleware" class="hash-link" aria-label="Manager.middleware的直接链接" title="Manager.middleware的直接链接" translate="no">​</a></h3>
<p>Manager 现在可以使用 <code>middleware</code> 属性来代替 <code>getMiddleware()</code> 方法。<a href="https://github.com/reactive/data-client/pull/3164" target="_blank" rel="noopener noreferrer" class="">#3164</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// handle action</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// handle action</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<div class="theme-admonition theme-admonition-tip admonition_WCGJ alert alert--success"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_pbrs"><p>为了向后兼容，<code>getMiddleware()</code> 仍然可用。</p></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="actiontypes-without-_type-suffix">不带 _TYPE 后缀的 actionTypes<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#actiontypes-without-_type-suffix" class="hash-link" aria-label="不带 _TYPE 后缀的 actionTypes的直接链接" title="不带 _TYPE 后缀的 actionTypes的直接链接" translate="no">​</a></h3>
<p>现在提供了更简洁的 action 类型名称（非破坏性变更——旧名称同样保留）。<a href="https://github.com/reactive/data-client/pull/3244" target="_blank" rel="noopener noreferrer" class="">#3244</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Middleware </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> actionTypes </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> actionTypes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">endpoint</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">stringify</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Middleware </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> actionTypes </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> actionTypes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">endpoint</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">stringify</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="getdefaultmanagers">getDefaultManagers()<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#getdefaultmanagers" class="hash-link" aria-label="getDefaultManagers()的直接链接" title="getDefaultManagers()的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/getDefaultManagers">getDefaultManagers()</a> 现在接受配置选项。<a href="https://github.com/reactive/data-client/pull/3161" target="_blank" rel="noopener noreferrer" class="">#3161</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getDefaultManagers </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Remove DevToolsManager</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> devToolsManager</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">null</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Configure DevToolsManager</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  devToolsManager</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    latency</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">predicate</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type </span><span class="token operator" style="color:rgb(137, 221, 255)">!==</span><span class="token plain"> actionTypes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use custom NetworkManager</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  networkManager</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IdlingNetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="networkmanager-constructor">NetworkManager 构造函数<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#networkmanager-constructor" class="hash-link" aria-label="NetworkManager 构造函数的直接链接" title="NetworkManager 构造函数的直接链接" translate="no">​</a></h3>
<p>为了更清晰，<a class="" href="https://dataclient.io/zh-Hans/docs/api/NetworkManager">NetworkManager</a> 的构造函数现在使用关键字参数。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">NetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">42</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">7</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">NetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> dataExpiryLength</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">42</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> errorExpiryLength</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">7</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="performance">性能<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#performance" class="hash-link" aria-label="性能的直接链接" title="性能的直接链接" translate="no">​</a></h2>
<p>React 18+ 的并发模式和自动批处理改变了我们应该采用的优化方式。等待空闲回调不再是最优选择——现在立即发起获取能带来更好的结果。内部改动利用闭包和 <code>Map</code> 数据结构来加快规范化和查找速度，同时移除臃肿的 polyfill 依赖显著缩小了包体积。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="immediate-fetching">立即获取<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#immediate-fetching" class="hash-link" aria-label="立即获取的直接链接" title="立即获取的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/NetworkManager">NetworkManager</a> 现在会立即发起获取，而不是等待空闲回调。<a href="https://github.com/reactive/data-client/pull/3146" target="_blank" rel="noopener noreferrer" class="">#3146</a></p>
<p>这让数据加载更快，对于渲染树复杂的应用尤其明显。</p>
<p>对于更喜欢之前行为的用户，<code>IdlingNetworkManager</code> 仍然可用：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> IdlingNetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getDefaultManagers </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  networkManager</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IdlingNetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="bundle-size">包体积<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#bundle-size" class="hash-link" aria-label="包体积的直接链接" title="包体积的直接链接" translate="no">​</a></h3>
<p>移除臃肿的 polyfill 包后，各个包现在<strong>缩小了 30%</strong>。<a href="https://github.com/reactive/data-client/pull/3384" target="_blank" rel="noopener noreferrer" class="">#3384</a></p>
<p>此外，polyfill 不再污染全局作用域。<a href="https://github.com/reactive/data-client/pull/3353" target="_blank" rel="noopener noreferrer" class="">#3353</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="normalization-performance">规范化性能<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#normalization-performance" class="hash-link" aria-label="规范化性能的直接链接" title="规范化性能的直接链接" translate="no">​</a></h3>
<p>内部 schema 接口的改动带来了 <strong>10% 的规范化性能提升</strong>。<a href="https://github.com/reactive/data-client/pull/3134" target="_blank" rel="noopener noreferrer" class="">#3134</a></p>
<p>使用 <code>Map</code> 代替普通对象来存储实体，在大型数据集上查找速度<strong>最多可快 32%</strong>。<a href="https://github.com/reactive/data-client/pull/3390" target="_blank" rel="noopener noreferrer" class="">#3390</a></p>
<center><div style="max-width:500px"></div><p><a href="https://reactive.github.io/data-client/dev/bench/" target="_blank" rel="noopener noreferrer" class="">历史基准测试</a> | <a href="https://github.com/reactive/data-client/tree/master/examples/benchmark" target="_blank" rel="noopener noreferrer" class="">查看基准测试</a></p></center>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemadata-modeling">Schema/数据建模<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#schemadata-modeling" class="hash-link" aria-label="Schema/数据建模的直接链接" title="Schema/数据建模的直接链接" translate="no">​</a></h2>
<p>Schema API 减少了常见模式的样板代码，同时支持更高级的用例。客户端连接现在可以跨任意实体工作（不再局限于嵌套关系），动态失效可以处理仅在服务端存在的删除逻辑，而像 <code>Entity.pk()</code> 默认使用 <code>id</code> 这样合理的默认值则消除了重复代码。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="query-joins">Query 连接<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#query-joins" class="hash-link" aria-label="Query 连接的直接链接" title="Query 连接的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> 现在可以接受 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Object">Object Schema</a>，从而实现跨多种实体类型的连接。<a href="https://github.com/reactive/data-client/pull/3165" target="_blank" rel="noopener noreferrer" class="">#3165</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Ticker</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  product_id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  price </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">product_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Stats</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  product_id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  last </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">product_id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Join Ticker and Stats by product_id</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> queryPrice </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> ticker</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> stats</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Stats </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> ticker</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> stats </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> ticker</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">price </span><span class="token operator" style="color:rgb(137, 221, 255)">??</span><span class="token plain"> stats</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token plain">last</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use in components</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> price </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">queryPrice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> product_id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'BTC-USD'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="entitymixin">EntityMixin<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#entitymixin" class="hash-link" aria-label="EntityMixin的直接链接" title="EntityMixin的直接链接" translate="no">​</a></h3>
<p>新增 <a class="" href="https://dataclient.io/zh-Hans/rest/api/EntityMixin">EntityMixin</a>，用于将 Entity 行为与现有的类组合。<a href="https://github.com/reactive/data-client/pull/3243" target="_blank" rel="noopener noreferrer" class="">#3243</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> EntityMixin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Your existing class</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Article</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  content </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  tags</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Add Entity behavior</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ArticleEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">EntityMixin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Article</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="entity-pk-default">Entity.pk() 默认值<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#entity-pk-default" class="hash-link" aria-label="Entity.pk() 默认值的直接链接" title="Entity.pk() 默认值的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#pk">Entity.pk()</a> 现在默认返回 <code>this.id</code>。<a href="https://github.com/reactive/data-client/pull/3188" target="_blank" rel="noopener noreferrer" class="">#3188</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Todo</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  completed </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Todo</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  completed </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">false</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="dynamic-invalidation">动态失效<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#dynamic-invalidation" class="hash-link" aria-label="动态失效的直接链接" title="动态失效的直接链接" translate="no">​</a></h3>
<p>在 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#process">Entity.process()</a> 中返回 <code>undefined</code>，即可根据响应数据动态地让实体<a class="" href="https://dataclient.io/zh-Hans/docs/concepts/expiry-policy#invalidate-entity">失效</a>。<a href="https://github.com/reactive/data-client/pull/3407" target="_blank" rel="noopener noreferrer" class="">#3407</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">PriceLevel</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  price </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  amount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation keyword" style="font-style:italic">this</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">price</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">process</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">price</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Invalidate when amount is 0</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">amount </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> price</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> amount </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="resource">resource()<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#resource" class="hash-link" aria-label="resource()的直接链接" title="resource()的直接链接" translate="no">​</a></h3>
<p>为求简洁，<code>createResource()</code> 已重命名为 <code>resource()</code>。<a href="https://github.com/reactive/data-client/pull/3158" target="_blank" rel="noopener noreferrer" class="">#3158</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> createResource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> resource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">resource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<div class="theme-admonition theme-admonition-note admonition_WCGJ alert alert--secondary"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_pbrs"><p>为了向后兼容，<code>createResource</code> 仍然会导出。</p></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="testing">测试<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#testing" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h2>
<p>测试应当简单。新的辅助函数使用合理的默认值，消除常见测试场景中的样板代码。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="renderdatahook">renderDataHook()<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#renderdatahook" class="hash-link" aria-label="renderDataHook()的直接链接" title="renderDataHook()的直接链接" translate="no">​</a></h3>
<p>新增的 <a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> 使用默认的 <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a>，消除了样板代码。<a href="https://github.com/reactive/data-client/pull/3238" target="_blank" rel="noopener noreferrer" class="">#3238</a></p>
<p>此外，为保持一致，<code>makeRenderDataClient()</code> 已重命名为 <a class="" href="https://dataclient.io/zh-Hans/docs/api/makeRenderDataHook">makeRenderDataHook()</a>（旧名称仍然可用）。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> renderDataHook </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/test'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> result </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">renderDataHook</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    initialFixtures</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        endpoint</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        response</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Test'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="garbage-collection">垃圾回收<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#garbage-collection" class="hash-link" aria-label="垃圾回收的直接链接" title="垃圾回收的直接链接" translate="no">​</a></h2>
<p>长时间运行的应用会在内存中积累过时数据。新的垃圾回收策略使用引用计数来跟踪哪些数据正被组件绑定，从而自动清理已过期的条目。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="gcpolicy">GCPolicy<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#gcpolicy" class="hash-link" aria-label="GCPolicy的直接链接" title="GCPolicy的直接链接" translate="no">​</a></h3>
<p>GCPolicy 可以自动对过时数据进行垃圾回收。<a href="https://github.com/reactive/data-client/pull/3343" target="_blank" rel="noopener noreferrer" class="">#3343</a></p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">GCPolicy</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">DataProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Run GC sweep every 10 minutes</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">gcPolicy</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">new</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript class-name" style="color:rgb(255, 203, 107)">GCPolicy</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> intervalMS</span><span class="token tag script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">60</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript operator" style="color:rgb(137, 221, 255)">*</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">1000</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript operator" style="color:rgb(137, 221, 255)">*</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript number" style="color:rgb(247, 140, 108)">10</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">children</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<p>配置过期行为：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">GCPolicy</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  intervalMS</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1000</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// How often to run GC</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  expiryMultiplier</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// How many stale lifetimes before GC</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></div></code></pre></div></div>
<p>使用 <code>ImmortalGCPolicy</code> 可以禁用垃圾回收（即之前的默认行为）：</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">ImmortalGCPolicy</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"> </span><span class="token imports maybe-class-name">DataProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">gcPolicy</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">new</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)"> </span><span class="token tag script language-javascript class-name" style="color:rgb(255, 203, 107)">ImmortalGCPolicy</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">children</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-improvements">其他改进<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#other-improvements" class="hash-link" aria-label="其他改进的直接链接" title="其他改进的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Collection 可与 Union 等多态 schema 配合使用 <a href="https://github.com/reactive/data-client/pull/3151" target="_blank" rel="noopener noreferrer" class="">#3151</a></li>
<li class="">Collection 支持嵌套参数（兼容 qs 库）<a href="https://github.com/reactive/data-client/pull/3281" target="_blank" rel="noopener noreferrer" class="">#3281</a></li>
<li class="">Interceptor 对 Manager 派发的 action 同样生效 <a href="https://github.com/reactive/data-client/pull/3365" target="_blank" rel="noopener noreferrer" class="">#3365</a></li>
<li class="">NetworkError 的消息中包含 URL，便于调试</li>
<li class="">React Native：使用 <code>InteractionManager.runAfterInteractions</code> 减少掉帧 <a href="https://github.com/reactive/data-client/pull/3127" target="_blank" rel="noopener noreferrer" class="">#3127</a></li>
<li class="">React Native：package.json exports 中新增 <code>react-native</code> 入口 <a href="https://github.com/reactive/data-client/pull/3371" target="_blank" rel="noopener noreferrer" class="">#3371</a></li>
<li class="">改进了 React 19 兼容性 <a href="https://github.com/reactive/data-client/pull/3279" target="_blank" rel="noopener noreferrer" class="">#3279</a></li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<!-- -->
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.14.0 @data-client/rest@^0.14.0 @data-client/test@^0.14.0 @data-client/img@^0.14.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.14.0 @data-client/rest@^0.14.0 @data-client/test@^0.14.0 @data-client/img@^0.14.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.14.0 @data-client/rest@^0.14.0 @data-client/test@^0.14.0 @data-client/img@^0.14.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.14.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.14.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.14.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.14.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="for-all-users">针对所有用户<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#for-all-users" class="hash-link" aria-label="针对所有用户的直接链接" title="针对所有用户的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="networkmanager">NetworkManager 立即发起获取<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#networkmanager" class="hash-link" aria-label="NetworkManager 立即发起获取的直接链接" title="NetworkManager 立即发起获取的直接链接" translate="no">​</a></h4>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/NetworkManager">NetworkManager</a> 现在会立即发起获取，而不是等待空闲。这提升了在 React 18+ 下的性能。<a href="https://github.com/reactive/data-client/pull/3146" target="_blank" rel="noopener noreferrer" class="">#3146</a></p>
<p>若要保留之前的行为，请使用 <code>IdlingNetworkManager</code>：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> IdlingNetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getDefaultManagers </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  networkManager</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">IdlingNetworkManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="custom-managers">针对自定义 Manager 作者<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#custom-managers" class="hash-link" aria-label="针对自定义 Manager 作者的直接链接" title="针对自定义 Manager 作者的直接链接" translate="no">​</a></h3>
<p>如果你没有自定义 <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a>，可以跳过本节。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="action-response">action.payload -&gt; action.response<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-response" class="hash-link" aria-label="action.payload -> action.response的直接链接" title="action.payload -> action.response的直接链接" translate="no">​</a></h4>
<p>对于处理 <a class="" href="https://dataclient.io/zh-Hans/docs/api/Actions#set_response">SET_RESPONSE</a> 的自定义 <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a>：<a href="https://github.com/reactive/data-client/pull/3141" target="_blank" rel="noopener noreferrer" class="">#3141</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Middleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Resolved with value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">payload</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Middleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'Resolved with value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="fetch-payload">fetchAction.payload 已移除<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#fetch-payload" class="hash-link" aria-label="fetchAction.payload 已移除的直接链接" title="fetchAction.payload 已移除的直接链接" translate="no">​</a></h4>
<p>对于处理 <a class="" href="https://dataclient.io/zh-Hans/docs/api/Actions#fetch">FETCH</a> 的自定义 <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a>：<a href="https://github.com/reactive/data-client/pull/3141" target="_blank" rel="noopener noreferrer" class="">#3141</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token constant" style="color:rgb(130, 170, 255)">FETCH_TYPE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Middleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">FETCH_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// consume fetch, and print the resolution</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">payload</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token constant" style="color:rgb(130, 170, 255)">FETCH_TYPE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Middleware</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">FETCH_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// consume fetch, and print the resolution</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        action</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">endpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">then</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="action-args">action.meta.args -&gt; action.args<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#action-args" class="hash-link" aria-label="action.meta.args -> action.args的直接链接" title="action.meta.args -> action.args的直接链接" translate="no">​</a></h4>
<p>Action 参数从 <code>meta</code> 移到了顶层。<a href="https://github.com/reactive/data-client/pull/3143" target="_blank" rel="noopener noreferrer" class="">#3143</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">meta</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="custom-schemas">针对自定义 Schema 作者<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#custom-schemas" class="hash-link" aria-label="针对自定义 Schema 作者的直接链接" title="针对自定义 Schema 作者的直接链接" translate="no">​</a></h3>
<p>如果你没有实现 <code>normalize()</code> 或 <code>denormalize()</code> 的自定义 schema，可以跳过本节。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schema-interface">Schema 接口变更<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#schema-interface" class="hash-link" aria-label="Schema 接口变更的直接链接" title="Schema 接口变更的直接链接" translate="no">​</a></h4>
<p><code>normalize()</code> 和 <code>denormalize()</code> 的接口已经改变。<a href="https://github.com/reactive/data-client/pull/3134" target="_blank" rel="noopener noreferrer" class="">#3134</a></p>
<p>这为所有用户带来了 10% 的性能提升。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemanormalize-visit">Schema.normalize visit()<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#schemanormalize-visit" class="hash-link" aria-label="Schema.normalize visit()的直接链接" title="Schema.normalize visit()的直接链接" translate="no">​</a></h4>
<p><code>visit()</code> 接口现在移除了与上下文无关的参数：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">/** Visits next data + schema while recurisvely normalizing */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Visit</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  creating</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">visit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  addEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  visitedEntities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  storeEntities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">visit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  processedEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>这些参数所需的信息，现在通过让 <code>visit()</code> 对它们形成<a href="https://en.wikipedia.org/wiki/Closure_(computer_programming)" target="_blank" rel="noopener noreferrer" class="">闭包</a>来提供。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemanormalize-interface">Schema.normalize 接口<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#schemanormalize-interface" class="hash-link" aria-label="Schema.normalize 接口的直接链接" title="Schema.normalize 接口的直接链接" translate="no">​</a></h4>
<p>从直接访问数据改为使用 <code>getEntity</code> 等函数：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">SchemaSimple</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">normalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">visit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      value</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      parent</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      key</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">addEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">checkLoop</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<p>我们还新增了 <code>checkLoop()</code>，它把 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a> 中的部分逻辑移到了核心的规范化算法中。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token doc-comment comment" style="color:rgb(105, 112, 152);font-style:italic">/** Returns true if a circular reference is found */</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">CheckLoop</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entityKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> pk</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> object</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemadenormalize-unvisit">Schema.denormalize unvisit()<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#schemadenormalize-unvisit" class="hash-link" aria-label="Schema.denormalize unvisit()的直接链接" title="Schema.denormalize unvisit()的直接链接" translate="no">​</a></h4>
<p><code>unvisit</code> 参数现在把 <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema">schema</a> 作为第一个参数：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">SchemaSimple</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">unvisit</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> input</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">T</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2024/07/13/v0.14-release-announcement#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如往常，如果你遇到任何问题或有疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>Manager</category>
            <category>性能</category>
        </item>
        <item>
            <title><![CDATA[v0.13：NextJS App Router、Expo、React 19、Redux]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native</link>
            <guid>https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native</guid>
            <pubDate>Mon, 17 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[支持 NextJS App Router 和 React 19，同时改进与 React Native 和 Expo 的兼容性]]></description>
            <content:encoded><![CDATA[<p>平台：</p>
<ul>
<li class=""><a href="https://nextjs.org/docs/app" target="_blank" rel="noopener noreferrer" class="">NextJS App Router</a></li>
<li class=""><a href="https://expo.dev/" target="_blank" rel="noopener noreferrer" class="">Expo</a></li>
<li class=""><a href="https://react.dev/blog/2024/12/05/react-19" target="_blank" rel="noopener noreferrer" class="">React 19</a></li>
</ul>
<p><strong>测试：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/docs/api/MockResolver">MockResolver</a> 已标记为 'client' 代码，以适配 NextJS App Router</li>
<li class="">导出 <a class="" href="https://dataclient.io/zh-Hans/docs/api/renderDataHook">renderDataHook()</a> - 兼容 React 17 和 18</li>
</ul>
<p>以下包已并入 <a href="https://www.npmjs.com/package/@data-client/react" target="_blank" rel="noopener noreferrer" class="">@data-client/react</a>：</p>
<ul>
<li class="">Redux</li>
<li class="">Hooks</li>
</ul>
<p><strong>其他改进</strong></p>
<ul>
<li class="">新增 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#controllerset">controller.set(Todo, { id }, { id, completed: false })</a></li>
<li class="">RestEndpoint.path <a class="" href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#path-strings">支持 +、* 和 {}</a></li>
<li class="">修复 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#ctrlfetch-and-unions">Union 在 controller.fetch() 中的返回值</a></li>
</ul>
<p><a class="" href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#migration-guide"><strong>破坏性变更：</strong></a></p>
<ul>
<li class="">actionTypes.SET_TYPE -&gt; <a href="https://dataclient.io/docs/api/Actions#set_response" target="_blank" rel="noopener noreferrer" class="">actionTypes.SET_RESPONSE_TYPE</a></li>
<li class="">SetAction -&gt; SetResponseAction</li>
<li class="">最低 React 版本 16.8.4 -&gt; 16.14</li>
</ul>
<div class="theme-admonition theme-admonition-note admonition_WCGJ alert alert--secondary"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_pbrs"><p>由于发布事故，0.12 版本被跳过了。</p></div></div>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="platforms">平台<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#platforms" class="hash-link" aria-label="平台的直接链接" title="平台的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="nextjs-app-router">NextJS App Router<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#nextjs-app-router" class="hash-link" aria-label="NextJS App Router的直接链接" title="NextJS App Router的直接链接" translate="no">​</a></h3>
<p>NextJS 12 引入了<a href="https://nextjs.org/docs/app" target="_blank" rel="noopener noreferrer" class="">在 '/app' 目录中进行路由的新方式</a>。它带来了进一步的性能提升，以及动态路由和嵌套路由。这使 NextJS 成为构建富动态应用的可行平台，而不仅仅是静态网站。</p>
<p><a href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching#fetching-data-on-the-client" target="_blank" rel="noopener noreferrer" class="">其他获取方式</a>需要缓慢的客户端获取；而 Reactive Data Client 则兼具 <abbr title="单页应用">SPA</abbr> 和
<abbr title="多页应用">MPA</abbr> 两者的优点。<a href="https://github.com/reactive/data-client/pull/3074" target="_blank" rel="noopener noreferrer" class="">#3074</a>、<a href="https://github.com/reactive/data-client/pull/3093" target="_blank" rel="noopener noreferrer" class="">#3093</a></p>
<p>与 MPA 一样，使用 Data Client 进行 SSR 意味着最快的<em>首次页面加载</em>。与 SPA 一样，Data Client 提供比 MPA 更快的<em>导航</em>、<em>客户端变更</em>以及<em>远程驱动的变更</em>（例如 websocket）。</p>
<p>此外，搭配 SSR 的 Data Client 相比其他客户端获取库依然保持性能优势。</p>
<figure class="perfChart_LYCy"><figcaption class="text--center text--bold margin-bottom--sm">与客户端获取的性能对比<div class="text--normal"><small>Bar lengths use a log scale</small></div></figcaption><div class="bars_HVEW" style="--perf-one:0%"><div class="row_OlYf" aria-hidden="true"><span></span><span class="oneLabel_y_xM">1x</span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">LCP</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:17.1591950743891%;--perf-split:0%"></span></span><span class="text--bold">3x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">Client fetch<!-- --> <!-- -->1200<!-- --> <!-- -->ms<!-- --> → <!-- -->Data Client<!-- --> <strong>400<!-- --> <!-- -->ms</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">Mutation</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:100%;--perf-split:0%"></span></span><span class="text--bold">603x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">Client fetch<!-- --> <!-- -->1810<!-- --> <!-- -->ms<!-- --> → <!-- -->Data Client<!-- --> <strong>3<!-- --> <!-- -->ms</strong></span></span></div><div class="anchor_tRSI row_OlYf" tabindex="0"><span class="label_dFrN">List to detail navigation</span><span class="track_Wj4m" aria-hidden="true"><span class="bar_eNox" style="width:29.79992018679698%;--perf-split:0%"></span></span><span class="text--bold">6.7x</span><span class="tip_L8pU tip_kDq8"><span class="bubble_XBbb">Client fetch<!-- --> <!-- -->310<!-- --> <!-- -->ms<!-- --> → <!-- -->Data Client<!-- --> <strong>46<!-- --> <!-- -->ms</strong></span></span></div></div></figure>
<center><video width="600" controls="" muted="" playsinline="" loop="" aria-label="一个 NextJS todo 应用在全新的隐身窗口中加载：服务端渲染的用户列表和 todo 立即可以交互，切换和添加 todo，切换用户时列表随之更新，整个过程没有任何客户端获取。"><source src="/zh-Hans/videos/blog/data-client-nextjs.mp4" type="video/mp4">一个 NextJS todo 应用在全新的隐身窗口中加载：服务端渲染的用户列表和 todo 立即可以交互，切换和添加 todo，切换用户时列表随之更新，整个过程没有任何客户端获取。</video></center>
<p><abbr title="Reactive Data Client">Data Client</abbr> 对 HTML 进行流式 SSR，优化了应用的初始加载体验。独特之处在于，<abbr title="Reactive Data Client">Data Client</abbr> 随后立即可交互，且客户端获取次数为 0。这是通过在 SSR 阶段用<a class="" href="https://dataclient.io/zh-Hans/docs/concepts/normalization">规范化数据</a>初始化<a class="" href="https://dataclient.io/zh-Hans/docs/getting-started/debugging#state-inspection">客户端 Store</a> 来实现的。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="usage">用法<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#usage" class="hash-link" aria-label="用法的直接链接" title="用法的直接链接" translate="no">​</a></h4>
<p>在你的<a href="https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required" target="_blank" rel="noopener noreferrer" class="">根布局</a>中渲染来自 <a href="https://dataclient.io/docs/guides/ssr#app-router" target="_blank" rel="noopener noreferrer" class="">/nextjs 入口</a>的 <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a>。</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">app/layout.tsx</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">DataProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/nextjs'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">AsyncBoundary</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RootLayout</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> children </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">html</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">body</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">          </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">header</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text">Title</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">header</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">          </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">AsyncBoundary</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">children</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">AsyncBoundary</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">          </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">footer</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">footer</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">body</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">html</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<div style="text-align:center"><a class="button button--primary" href="https://dataclient.io/zh-Hans/docs/guides/ssr#nextjs">完整 NextJS 指南</a></div>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="mutations-demo">变更演示<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#mutations-demo" class="hash-link" aria-label="变更演示的直接链接" title="变更演示的直接链接" translate="no">​</a></h4>
<div class="card_wNtI"><p class="cardTitle_q8VY">探索 nextjs 示例</p><div class="cardLinks_EoYh"><a href="https://stackblitz.com/github/reactive/data-client/tree/master/examples/nextjs?file=components%2Ftodo%2FTodoList.tsx%2Capp%2Flayout.tsx" target="_blank" rel="noopener noreferrer" class="button button--primary">在 StackBlitz 中打开</a><a href="https://github.com/reactive/data-client/tree/master/examples/nextjs" target="_blank" rel="noopener noreferrer" class="button button--secondary">查看源码</a></div></div><div class="wrapper_ZhQy"><span class="loading_rblT" aria-hidden="true">正在加载演示…</span><iframe width="100%" height="500" title="nextjs 在 StackBlitz 上的演示" class="frame_PtfY"></iframe></div><p style="text-align:center"><a class="button button--secondary button--sm" href="https://dataclient.io/zh-Hans/demos">更多演示</a></p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="live-data-demo">实时数据演示<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#live-data-demo" class="hash-link" aria-label="实时数据演示的直接链接" title="实时数据演示的直接链接" translate="no">​</a></h4>
<div><iframe src="https://coin-app-lake.vercel.app" width="100%" height="400"></iframe><p style="text-align:center"><a href="https://coin-app-lake.vercel.app/" target="_blank" rel="noopener noreferrer" class="button button--secondary button--sm">在新标签页中打开</a>&nbsp;<a href="https://github.com/reactive/coin-app" target="_blank" rel="noopener noreferrer" class="button button--secondary button--sm">Github</a></p></div>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-ssr">其他 SSR<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#other-ssr" class="hash-link" aria-label="其他 SSR的直接链接" title="其他 SSR的直接链接" translate="no">​</a></h4>
<p>新增 <a class="" href="https://dataclient.io/zh-Hans/docs/guides/ssr#express-js-ssr">/ssr 入口</a>——完全不再需要 @data-client/ssr 包 <a href="https://github.com/reactive/data-client/commit/d1b9e96dffe69527f9ce0ebff4727f0b1226c9d5" target="_blank" rel="noopener noreferrer" class=""><code>d1b9e96</code></a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createPersistedStore</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createServerDataComponent</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports"></span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/ssr'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createPersistedStore</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createServerDataComponent</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports"></span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/ssr'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>这使得将 Data Client 轻松集成到任何 SSR 框架成为可能。我们欢迎为集成任何开源框架所做的<a href="https://github.com/reactive/data-client/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer" class="">贡献</a>。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="expo">Expo<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#expo" class="hash-link" aria-label="Expo的直接链接" title="Expo的直接链接" translate="no">​</a></h3>
<p>我们已开始着手 Expo/ExpoGo 演示，并借此发现并修复了这些集成中的一些兼容性问题。如果有我们遗漏的问题，请<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">报告</a>给我们。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="react-19">React 19<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#react-19" class="hash-link" aria-label="React 19的直接链接" title="React 19的直接链接" translate="no">​</a></h3>
<p>我们现在支持 React 19。<a href="https://github.com/reactive/data-client/pull/3071" target="_blank" rel="noopener noreferrer" class="">#3071</a></p>
<p>这需要放弃对低于 16.14 版本的支持，因为我们必须使用 React 自身导出的 jsx
运行时。这还带来了减小包体积的额外好处。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="redux">Redux<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#redux" class="hash-link" aria-label="Redux的直接链接" title="Redux的直接链接" translate="no">​</a></h3>
<p>新增 <a class="" href="https://dataclient.io/zh-Hans/docs/guides/redux">@data-client/react/redux</a> <a href="https://github.com/reactive/data-client/pull/3099" target="_blank" rel="noopener noreferrer" class="">#3099</a>。这样就不再需要单独的 @data-client/redux 包。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  </span><span class="token imports maybe-class-name">ExternalDataProvider</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  </span><span class="token imports maybe-class-name">PromiseifyMiddleware</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  applyManager</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  initialState</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createReducer</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  prepareStore</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports"></span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/redux'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  </span><span class="token imports maybe-class-name">ExternalDataProvider</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  </span><span class="token imports maybe-class-name">PromiseifyMiddleware</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  applyManager</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  initialState</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  createReducer</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports">  prepareStore</span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token imports"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token imports"></span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/redux'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>为 prepareStore() 新增 middlewares 参数 <a href="https://github.com/reactive/data-client/pull/3099" target="_blank" rel="noopener noreferrer" class="">#3099</a></p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> store</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">prepareStore</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  initialState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  managers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token maybe-class-name">Controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  otherReducers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  extraMiddlewares</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="controllerset">controller.set()<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#controllerset" class="hash-link" aria-label="controller.set()的直接链接" title="controller.set()的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#set">controller.set()</a> 可以更新任意 <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema#queryable">Queryable</a> <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema#schema-overview">Schema</a>。<a href="https://github.com/reactive/data-client/pull/3105" target="_blank" rel="noopener noreferrer" class="">#3105</a>、<a href="https://github.com/reactive/data-client/pull/3129" target="_blank" rel="noopener noreferrer" class="">#3129</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'tell me friends how great Data Client is'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>当需要使用派生数据时，值可以是函数。这能<a href="https://react.dev/reference/react/useState#updating-state-based-on-the-previous-state" target="_blank" rel="noopener noreferrer" class="">避免竞态条件</a>。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'2'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Article</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> article </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> article</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_WCGJ alert alert--secondary"><div class="admonitionHeading_GCBg"><span class="admonitionIcon_L39b"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_pbrs"><p>响应必须包含足以计算 Entity.pk() 的值</p></div></div>
<p>这让通过 <a class="" href="https://dataclient.io/zh-Hans/docs/concepts/managers">Manager</a> 操作 store 变得更加直接。例如，我们可以在收到 websocket 消息时直接设置 <code>Ticker</code> 实体：</p>
<!-- -->
<div class="card_wNtI"><p class="cardTitle_q8VY">探索 coin-app 示例</p><div class="cardLinks_EoYh"><a href="https://stackblitz.com/github/reactive/data-client/tree/master/examples/coin-app?file=src%2FgetManagers.ts%2Csrc%2Fresources%2FTicker.ts%2Csrc%2Fpages%2FAssetDetail%2FAssetPrice.tsx%2Csrc%2Fresources%2FStreamManager.ts" target="_blank" rel="noopener noreferrer" class="button button--primary">在 StackBlitz 中打开</a><a href="https://github.com/reactive/data-client/tree/master/examples/coin-app" target="_blank" rel="noopener noreferrer" class="button button--secondary">查看源码</a></div></div><div class="wrapper_ZhQy"><span class="loading_rblT" aria-hidden="true">正在加载演示…</span><iframe width="100%" height="600" title="coin-app 在 StackBlitz 上的演示" class="frame_PtfY"></iframe></div><p style="text-align:center"><a class="button button--secondary button--sm" href="https://dataclient.io/zh-Hans/demos">更多演示</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="type-improvements">类型改进<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#type-improvements" class="hash-link" aria-label="类型改进的直接链接" title="类型改进的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>改进 <a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller">controller</a> 各方法的类型匹配 <a href="https://github.com/reactive/data-client/pull/3043" target="_blank" rel="noopener noreferrer" class="">#3043</a></p>
</li>
<li class="">
<p>改进 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useFetch">useFetch()</a> 的参数类型匹配，使其与 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useSuspense">useSuspense()</a> 类似 <a href="https://github.com/reactive/data-client/pull/3043" target="_blank" rel="noopener noreferrer" class="">#3043</a></p>
</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="rest-changes">REST 变更<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#rest-changes" class="hash-link" aria-label="REST 变更的直接链接" title="REST 变更的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="path-strings">路径字符串<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#path-strings" class="hash-link" aria-label="路径字符串的直接链接" title="路径字符串的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#path">RestEndpoint.path</a> 支持 +、* 和 {}。<a href="https://github.com/reactive/data-client/commit/a6b4f4aabbfd06f5106a96e809a6c1a5e7045172" target="_blank" rel="noopener noreferrer" class=""><code>a6b4f4a</code></a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getThing </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/:attr1?{-:attr2}?{-:attr3}?'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">getThing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> attr1</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'hi'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">getThing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> attr2</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'hi'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">getThing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> attr3</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'hi'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">getThing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> attr1</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'hi'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> attr3</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'ho'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">getThing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> attr2</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'hi'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> attr3</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'ho'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="ctrlfetch-and-unions">ctrl.fetch() 与 Union<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#ctrlfetch-and-unions" class="hash-link" aria-label="ctrl.fetch() 与 Union的直接链接" title="ctrl.fetch() 与 Union的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#fetch">ctrl.fetch()</a> 返回值中的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a> 值现在是其 Entity 类的实例。<a href="https://github.com/reactive/data-client/pull/3063" target="_blank" rel="noopener noreferrer" class="">#3063</a></p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh small_xksL"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">Feed</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">useFeed</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getFeed </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./Feed'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useFeedHandler</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">handleSomething</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> feed </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getFeed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> feed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">item </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">item</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">type </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'link'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// we can use class defined getter</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> item</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">anchor</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> handleSomething</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span>
</span></pre></div></div></div></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<!-- -->
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.13.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.13.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.13.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.13.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="set_response_type">actionTypes.SET_TYPE -&gt; actionTypes.SET_RESPONSE_TYPE<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#set_response_type" class="hash-link" aria-label="actionTypes.SET_TYPE -> actionTypes.SET_RESPONSE_TYPE的直接链接" title="actionTypes.SET_TYPE -> actionTypes.SET_RESPONSE_TYPE的直接链接" translate="no">​</a></h3>
<p>如果你编写了处理 <code>actionTypes.SET_TYPE</code> 的自定义 Manager，需要将其重命名为 <a class="" href="https://dataclient.io/zh-Hans/docs/api/Actions#set_response">actionTypes.SET_RESPONSE_TYPE</a>。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token maybe-class-name">Middleware</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> actionTypes </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> actionTypes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SET_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">endpoint</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">stringify</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// actions must be explicitly passed to next middleware</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">type</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token maybe-class-name">Manager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token maybe-class-name">Middleware</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> actionTypes </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  middleware</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">Middleware</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> controller </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">switch</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">case</span><span class="token plain"> actionTypes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token constant" style="color:rgb(130, 170, 255)">SET_RESPONSE_TYPE</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token console class-name" style="color:rgb(255, 203, 107)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">info</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">endpoint</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">name</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string string" style="color:rgb(195, 232, 141)"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation constant" style="color:rgb(130, 170, 255)">JSON</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation function" style="color:rgb(130, 170, 255)">stringify</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">action</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">response</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// actions must be explicitly passed to next middleware</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">default</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="set-action">SetAction -&gt; SetResponseAction<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#set-action" class="hash-link" aria-label="SetAction -> SetResponseAction的直接链接" title="SetAction -> SetResponseAction的直接链接" translate="no">​</a></h3>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="react-version">React 16.14+<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#react-version" class="hash-link" aria-label="React 16.14+的直接链接" title="React 16.14+的直接链接" translate="no">​</a></h3>
<p>将最低 React 版本从 16.8.4 提高到 16.14。无需修改任何代码。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> react@16.14 react-dom@16.14</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> react@16.14 react-dom@16.14</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> react@16.14 react-dom@16.14</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/react@16.14"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"react-dom"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/react-dom@16.14"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="data-provider">CacheProvider -&gt; DataProvider<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#data-provider" class="hash-link" aria-label="CacheProvider -> DataProvider的直接链接" title="CacheProvider -> DataProvider的直接链接" translate="no">​</a></h3>
<p>迁移到 <a class="" href="https://dataclient.io/zh-Hans/docs/api/DataProvider">DataProvider</a> 以兼容未来版本。它同时也以
<code>CacheProvider</code> 的名称导出，因此这不是破坏性变更。<a href="https://github.com/reactive/data-client/pull/3095" target="_blank" rel="noopener noreferrer" class="">#3095</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">CacheProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">ReactDOM</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react-dom'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">createRoot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token dom variable" style="color:rgb(191, 199, 213)">document</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">App</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">DataProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">ReactDOM</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react-dom'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token maybe-class-name">ReactDOM</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">createRoot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token dom variable" style="color:rgb(191, 199, 213)">document</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">render</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">App</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">DataProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2024/06/17/v0.13-nextjs-app-router-expogo-native#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如既往，如果你遇到任何问题或有任何疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>NextJS</category>
            <category>Expo</category>
            <category>React Native</category>
        </item>
        <item>
            <title><![CDATA[v0.11 Query、Queryable 与 useQuery]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery</link>
            <guid>https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery</guid>
            <pubDate>Mon, 08 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Data Client 0.11 带来了全新的记忆化直接 schema 访问能力：通过 useQuery hook，可以用任意 Queryable Schema 直接访问 store]]></description>
            <content:encoded><![CDATA[<p>除了<a href="https://react.dev/learn/choosing-the-state-structure" target="_blank" rel="noopener noreferrer" class="">规范化状态</a>带来的性能和数据完整性收益之外，我们还获得了一项额外的好处：能够安全地直接访问并查询 store。</p>
<p>在本次发布中，我们围绕 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery#queryable">Queryable Schema</a> 的概念统一并简化了这一功能。它们包括
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/All">All</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a>
和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a></p>
<p>这一变化最大的影响是引入了新的 hook <a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#usequery">useQuery()</a>，它允许使用
<a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery#queryable">Queryable Schema</a> 直接查找 store。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  username </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  groupId </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> index </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'username'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>同样地，我们可以通过 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#controllerget">controller.get</a> 在 controller 和 snapshot 中查找 Queryable</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>此外，我们还投入了更多的<a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#performance">性能改进</a>，使大多数操作的性能提升了约 2 倍，而 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> 则快了 16 倍。</p>
<center><a class="button button--secondary" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#migration-guide">迁移指南</a></center>
<p><strong>破坏性变更：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#removed-index">useCache(new Index(MyEntity)) -&gt; useQuery(MyEntity)</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#query-migration">new Query -&gt; new schema.Query</a>
<ul>
<li class="">useCache(myQuery) -&gt; useQuery(myQuery)</li>
</ul>
</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#snap.abort">new AbortOptimistic() -&gt; snapshot.abort</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#shouldupdate">Entity.useIncoming → Entity.shouldUpdate</a></li>
</ul>
<p><a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#other-improvements"><strong>其他亮点：</strong></a></p>
<ul>
<li class="">useCache() 接受带有 sideEffects 的 Endpoint（例如 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#update">Resource.update</a>）</li>
<li class="">允许 Entity.pk() 返回数字。</li>
<li class="">2 到 16 倍的<a class="" href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#performance">性能改进</a></li>
</ul>
<!-- -->
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="querable">Queryable<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#querable" class="hash-link" aria-label="Queryable的直接链接" title="Queryable的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/schema#queryable">Queryable</a> schema 需要一个返回非空值的 <code>queryKey()</code> 方法。它们包括
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity">Entity</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/All">All</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a>、<a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a>
和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Union">Union</a>。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">interface</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Queryable</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    getEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> GetEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    getIndex</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> GetIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// `{}` means non-void</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemaquery">schema.Query<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#schemaquery" class="hash-link" aria-label="schema.Query的直接链接" title="schema.Query的直接链接" translate="no">​</a></h3>
<p><code>Query</code> 之前是作为 Endpoint 实现的。既然我们现在有了直接获取 Queryable
schema 的方法，就可以干脆让 Query 本身也成为一个 Queryable schema。它的用法基本保持不变，允许对 store 中的值进行任意计算。<a href="https://github.com/reactive/data-client/pull/2921" target="_blank" rel="noopener noreferrer" class="">#2921</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUserCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">All</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">!==</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">user </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> isAdmin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> adminCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>schema.Query 现在不再允许使用非 Queryable 的 schema。</p>
<div class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA standaloneEditor_OHub"><div class="playgroundTextEdit_rt2K"><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-ts" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getBob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Array is not Queryable</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Array</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> bob</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  thing </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> thing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span>
</span></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="controllerget">controller.get / snapshot.get<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#controllerget" class="hash-link" aria-label="controller.get / snapshot.get的直接链接" title="controller.get / snapshot.get的直接链接" translate="no">​</a></h3>
<p>现在只需一个 Queryable Schema 即可<a class="" href="https://dataclient.io/zh-Hans/docs/api/Controller#get">访问 store</a>——不再需要一整个 Endpoint。
<a href="https://github.com/reactive/data-client/pull/2921" target="_blank" rel="noopener noreferrer" class="">#2921</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> data</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> post </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>由于我们不再需要访问其他 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#members">Resource 成员</a>来获取 <code>Post</code>，就可以使用简单得多的 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#extend-new">Resource.extend()</a> 重载。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> PostResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/posts/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  vote</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/posts/:id/vote'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    method</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'POST'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> data</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> PostResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/posts/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'vote'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/posts/:id/vote'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  method</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'POST'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> post </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> post</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="usequery">useQuery<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#usequery" class="hash-link" aria-label="useQuery的直接链接" title="useQuery的直接链接" translate="no">​</a></h3>
<p>从 store 中渲染任意 <a class="" href="https://dataclient.io/zh-Hans/rest/api/schema#queryable">Queryable Schema</a>。
<a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> 是高效渲染聚合计算的绝佳搭档，例如那些使用 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy#browser_compatibility" target="_blank" rel="noopener noreferrer" class="">groupBy</a>、
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map" target="_blank" rel="noopener noreferrer" class="">map</a>、<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce" target="_blank" rel="noopener noreferrer" class="">reduce</a> 和 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter" target="_blank" rel="noopener noreferrer" class="">filter</a> 的计算。<a href="https://github.com/reactive/data-client/pull/2921" target="_blank" rel="noopener noreferrer" class="">#2921</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  username </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  groupId </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> index </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'username'</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUserCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">All</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">!==</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">user </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> isAdmin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> adminCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> UserCollection </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Collection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">argsKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">urlParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> groupId</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">urlParams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> usersInGroup </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">UserCollection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> groupId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'5'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="performance">性能<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#performance" class="hash-link" aria-label="性能的直接链接" title="性能的直接链接" translate="no">​</a></h2>
<p>对缓存系统以及所有关键代码路径的进一步优化，为最常见的操作带来了
2 倍的可观提升。再加上新增的<a href="https://github.com/reactive/data-client/pull/2978" target="_blank" rel="noopener noreferrer" class="">查询缓存能力</a>，我们的 Query 排序基准测试更是取得了令人印象深刻的 16 倍提升。</p>
<p>这些都叠加在原有的（最高 23 倍）<a class="" href="https://dataclient.io/zh-Hans/docs/concepts/normalization#benchmarks">相对旧版 normalizr</a> 库的领先优势之上。</p>
<center><div style="max-width:600px"></div><p><a href="https://reactive.github.io/data-client/dev/bench/" target="_blank" rel="noopener noreferrer" class="">历史基准测试</a> | <a href="https://github.com/reactive/data-client/tree/master/examples/benchmark" target="_blank" rel="noopener noreferrer" class="">查看基准测试</a></p></center>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-improvements">其他改进<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#other-improvements" class="hash-link" aria-label="其他改进的直接链接" title="其他改进的直接链接" translate="no">​</a></h2>
<ul>
<li class="">useCache() 接受带有 sideEffects 的 Endpoint（例如 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#update">Resource.update</a>）<a href="https://github.com/reactive/data-client/pull/2963" target="_blank" rel="noopener noreferrer" class="">#2963</a>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> lastCreated </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">MyResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">push</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
</li>
<li class="">允许 pk 返回数字 <a href="https://github.com/reactive/data-client/pull/2961" target="_blank" rel="noopener noreferrer" class="">#2961</a>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation keyword" style="font-style:italic">this</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation">id</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
</li>
<li class="">类型<!-- -->
<ul>
<li class="">在使用<a href="https://www.typescriptlang.org/tsconfig#strictNullChecks" target="_blank" rel="noopener noreferrer" class="">宽松空值检查</a>且没有 body 参数时，改进 .extend() 的类型推断 <a href="https://github.com/reactive/data-client/pull/2962" target="_blank" rel="noopener noreferrer" class="">#2962</a>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Parameters</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token keyword" style="font-style:italic">typeof</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/test'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/test2'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><br></div></code></pre></div></div>
</li>
<li class="">Collection 默认的 Args 类型为：<a href="https://github.com/reactive/data-client/commit/8377e0a157419f0f4c237c392a895fec1772854d" target="_blank" rel="noopener noreferrer" class="">8377e</a>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">urlParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Record</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">urlParams</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Record</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><br></div></code></pre></div></div>
</li>
</ul>
</li>
<li class="">修复<!-- -->
<ul>
<li class="">schema.All 反规范化的 INVALID 情况在生产构建中进行类名混淆时也应正常工作 <a href="https://github.com/reactive/data-client/pull/2954" target="_blank" rel="noopener noreferrer" class="">#2954</a>
<ul>
<li class="">输入为 <code>undefined</code> 时，<code>unvisit()</code> 始终返回 <code>undefined</code>。</li>
<li class=""><code>All</code> 在 <code>queryKey()</code> 中返回 INVALID，以使此前 <code>unvisit()</code> 中的特殊情况（给定实体没有表项时）失效</li>
</ul>
</li>
<li class="">缺失的嵌套实体在出现后应该能够显示出来 <a href="https://github.com/reactive/data-client/pull/2956" target="_blank" rel="noopener noreferrer" class="">#2956</a>、<a href="https://github.com/reactive/data-client/pull/2961" target="_blank" rel="noopener noreferrer" class="">#2961</a></li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<!-- -->
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.11.0 @data-client/rest@^0.11.0 @data-client/test@^0.11.0 @data-client/img@^0.11.0 @data-client/hooks@^0.11.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.11.0 @data-client/rest@^0.11.0 @data-client/test@^0.11.0 @data-client/img@^0.11.0 @data-client/hooks@^0.11.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.11.0 @data-client/rest@^0.11.0 @data-client/test@^0.11.0 @data-client/img@^0.11.0 @data-client/hooks@^0.11.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.11.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.11.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.11.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.11.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/hooks"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/hooks@^0.11.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="removed-index">移除 Index<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#removed-index" class="hash-link" aria-label="移除 Index的直接链接" title="移除 Index的直接链接" translate="no">​</a></h3>
<p>直接在 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery">useQuery</a> 中使用 Entity 即可</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token maybe-class-name">UserIndex</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Index</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">UserIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> bob </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> username</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'bob'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="query-migration">new Query -&gt; new schema.Query<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#query-migration" class="hash-link" aria-label="new Query -> new schema.Query的直接链接" title="new Query -> new schema.Query的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Query">Query</a> 现在是一个 schema；与 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useQuery">useQuery</a> 搭配使用</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUserCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access maybe-class-name" style="color:rgb(130, 170, 255)">All</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">!==</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">user </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">isAdmin</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> isAdmin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> adminCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUserCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access maybe-class-name" style="color:rgb(130, 170, 255)">Query</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access maybe-class-name" style="color:rgb(130, 170, 255)">All</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">isAdmin </span><span class="token operator" style="color:rgb(137, 221, 255)">!==</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">user </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">isAdmin</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> isAdmin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> entries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> userCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> adminCount </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useQuery</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUserCount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> isAdmin</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="snap.abort">new AbortOptimistic() -&gt; snapshot.abort<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#snap.abort" class="hash-link" aria-label="new AbortOptimistic() -> snapshot.abort的直接链接" title="new AbortOptimistic() -> snapshot.abort的直接链接" translate="no">​</a></h3>
<p><a href="https://dataclient.io/docs/api/Snapshot#abort" target="_blank" rel="noopener noreferrer" class="">snapshot.abort</a> 让你不再需要导入 AbortOptimistic <a href="https://github.com/reactive/data-client/pull/2957" target="_blank" rel="noopener noreferrer" class="">#2957</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AbortOptimistic</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">getOptimisticResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> data </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getResponse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">throw</span><span class="token plain"> snapshot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">abort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    votes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">votes </span><span class="token operator" style="color:rgb(137, 221, 255)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="shouldupdate">Entity.useIncoming → Entity.shouldUpdate<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#shouldupdate" class="hash-link" aria-label="Entity.useIncoming → Entity.shouldUpdate的直接链接" title="Entity.useIncoming → Entity.shouldUpdate的直接链接" translate="no">​</a></h3>
<p>让 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#shouldupdate">Entity.shouldUpdate</a> 的命名与 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Entity#shouldreorder">Entity.shouldReorder</a> 保持一致 <a href="https://github.com/reactive/data-client/pull/2972" target="_blank" rel="noopener noreferrer" class="">#2972</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useIncoming</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    existingMeta</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> date</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    incomingMeta</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> date</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    existing</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    incoming</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">deepEquals</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">existing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> incoming</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">shouldUpdate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    existingMeta</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> date</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    incomingMeta</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> date</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    existing</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    incoming</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token function" style="color:rgb(130, 170, 255)">deepEquals</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">existing</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> incoming</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="usedle-reactive-native-focus-handling">useDLE() 在 React Native 中的焦点处理<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#usedle-reactive-native-focus-handling" class="hash-link" aria-label="useDLE() 在 React Native 中的焦点处理的直接链接" title="useDLE() 在 React Native 中的焦点处理的直接链接" translate="no">​</a></h3>
<p>与 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useSuspense">useSuspense()</a> 和 <a class="" href="https://dataclient.io/zh-Hans/docs/api/useFetch">useFetch()</a> 一样，<a class="" href="https://dataclient.io/zh-Hans/docs/api/useDLE">useDLE()</a> 现在可能会在焦点事件发生时重新验证数据。</p>
<p>使用 React Navigation 时，如果数据被视为过时，useDLE() 会在获得焦点时触发获取。</p>
<p>这可能导致比以前更多的获取请求。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="potential-but-unlikely-breaking-changes">可能但不太会遇到的破坏性变更<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#potential-but-unlikely-breaking-changes" class="hash-link" aria-label="可能但不太会遇到的破坏性变更的直接链接" title="可能但不太会遇到的破坏性变更的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schemainfer---schemaquerykey-2977">Schema.infer() -&gt; Schema.queryKey() <a href="https://github.com/reactive/data-client/pull/2977" target="_blank" rel="noopener noreferrer" class="">#2977</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#schemainfer---schemaquerykey-2977" class="hash-link" aria-label="schemainfer---schemaquerykey-2977的直接链接" title="schemainfer---schemaquerykey-2977的直接链接" translate="no">​</a></h4>
<p>大多数人都没有重写过 <code>infer()</code> 方法。如果你重写了，需要将其重命名为 <code>queryKey()</code>，并同时更新参数列表。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">infer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    indexes</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> NormalizedIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    recurse</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    entities</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">SILLYCONDITION</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token operator" style="color:rgb(137, 221, 255)">?.</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">someId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> someId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">super</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">infer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> indexes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> recurse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">readonly</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">args</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    getEntity</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> GetEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    getIndex</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> GetIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token constant" style="color:rgb(130, 170, 255)">SILLYCONDITION</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> someId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> someId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">super</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> queryKey</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h5 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="getentitykey-pk">getEntity(key, pk?)<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#getentitykey-pk" class="hash-link" aria-label="getEntity(key, pk?)的直接链接" title="getEntity(key, pk?)的直接链接" translate="no">​</a></h5>
<p>传入一个参数时获取某一类型的全部实体，传入两个参数时获取单个实体</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">One argument</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> entitiesEntry </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entitiesEntry </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">undefined</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">INVALID</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> Object</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entitiesEntry</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">map</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  entity </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> entity </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;&amp;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Two arguments</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">getEntity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="getindexkey-indexname-value">getIndex(key, indexName, value)<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#getindexkey-indexname-value" class="hash-link" aria-label="getIndex(key, indexName, value)的直接链接" title="getIndex(key, indexName, value)的直接链接" translate="no">​</a></h5>
<p>返回索引条目（value-&gt;pk 的映射）</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">indexName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getIndex</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> indexName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="always-normalize-pk-to-string-type-2961">pk 始终规范化为字符串类型 <a href="https://github.com/reactive/data-client/pull/2961" target="_blank" rel="noopener noreferrer" class="">#2961</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#always-normalize-pk-to-string-type-2961" class="hash-link" aria-label="always-normalize-pk-to-string-type-2961的直接链接" title="always-normalize-pk-to-string-type-2961的直接链接" translate="no">​</a></h4>
<p>这是对 store 中内容的一个细微变化。这很可能只在直接使用 <a href="https://www.npmjs.com/package/@data-client/normalizr" target="_blank" rel="noopener noreferrer" class="">@data-client/normalizr</a>
时才有影响。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"Article"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"123"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"author"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8472</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">123</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"A Great Article"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"User"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"8472"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8472</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Paul"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"Article"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"123"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"author"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"8472"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">123</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"A Great Article"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"User"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"8472"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8472</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Paul"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="stateresults---stateendpoints-2971">state.results -&gt; state.endpoints <a href="https://github.com/reactive/data-client/pull/2971" target="_blank" rel="noopener noreferrer" class="">#2971</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#stateresults---stateendpoints-2971" class="hash-link" aria-label="stateresults---stateendpoints-2971的直接链接" title="stateresults---stateendpoints-2971的直接链接" translate="no">​</a></h4>
<p>这很可能只在直接使用 <a href="https://www.npmjs.com/package/@data-client/core" target="_blank" rel="noopener noreferrer" class="">@data-client/core</a> 时才有影响，因为内部状态的结构对 <a href="https://www.npmjs.com/package/@data-client/react" target="_blank" rel="noopener noreferrer" class="">@data-client/react</a> 来说是不透明的。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"entities"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"Article"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"5"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"content"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"more things here"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"hi"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"results"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"GET http://test.com/articles/5"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"5"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-json codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-json codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"entities"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"Article"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token property">"5"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"content"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"more things here"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"id"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">"title"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"hi"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">"endpoints"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">"GET http://test.com/articles/5"</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"5"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="inferresults---memobuildquerykey-2977-2978">inferResults() -&gt; memo.buildQueryKey() <a href="https://github.com/reactive/data-client/pull/2977" target="_blank" rel="noopener noreferrer" class="">#2977</a>、<a href="https://github.com/reactive/data-client/pull/2978" target="_blank" rel="noopener noreferrer" class="">#2978</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#inferresults---memobuildquerykey-2977-2978" class="hash-link" aria-label="inferresults---memobuildquerykey-2977-2978的直接链接" title="inferresults---memobuildquerykey-2977-2978的直接链接" translate="no">​</a></h4>
<p>这些方法由 <a href="https://www.npmjs.com/package/@data-client/core" target="_blank" rel="noopener noreferrer" class="">@data-client/core</a> 和 <a href="https://www.npmjs.com/package/@data-client/normalizr" target="_blank" rel="noopener noreferrer" class="">@data-client/normalizr</a> 导出。</p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="denormalizecached---memodenormalize-2978">denormalizeCached() -&gt; memo.denormalize() <a href="https://github.com/reactive/data-client/pull/2978" target="_blank" rel="noopener noreferrer" class="">#2978</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#denormalizecached---memodenormalize-2978" class="hash-link" aria-label="denormalizecached---memodenormalize-2978的直接链接" title="denormalizecached---memodenormalize-2978的直接链接" translate="no">​</a></h4>
<p>由 <a href="https://www.npmjs.com/package/@data-client/normalizr" target="_blank" rel="noopener noreferrer" class="">@data-client/normalizr</a> 导出</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> endpointCache </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">WeakEntityMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> entityCache </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token function" style="color:rgb(130, 170, 255)">denormalizeCached</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  entityCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  endpointCache</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> memo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MemoCached</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">memo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">denormalize</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  input</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  state</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">entities</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="weakentitymap---weakdependencymap-2978">WeakEntityMap -&gt; WeakDependencyMap <a href="https://github.com/reactive/data-client/pull/2978" target="_blank" rel="noopener noreferrer" class="">#2978</a><a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#weakentitymap---weakdependencymap-2978" class="hash-link" aria-label="weakentitymap---weakdependencymap-2978的直接链接" title="weakentitymap---weakdependencymap-2978的直接链接" translate="no">​</a></h4>
<p>由 <a href="https://www.npmjs.com/package/@data-client/normalizr" target="_blank" rel="noopener noreferrer" class="">@data-client/normalizr</a> 导出</p>
<p>我们将这一数据类型泛化，使其可以用于其他依赖。</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">WeakEntityMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">WeakDependencyMap</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)">EntityPath</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2024/04/08/v0.11-queries-querable-usequery#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如既往，如果你遇到任何问题或有任何疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>Queryable</category>
            <category>Schema</category>
        </item>
        <item>
            <title><![CDATA[v0.10：一致的 null 处理、URL 工具函数]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities</link>
            <guid>https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities</guid>
            <pubDate>Thu, 15 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Data Client 0.10 为所有 schema 带来一致的 null 处理，为 RestEndpoint 新增 URL 构造工具函数，并修复了 DevTools 的内存泄漏。]]></description>
            <content:encoded><![CDATA[<p>本次发布聚焦于一致性和可扩展性。<a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#null-consistency">null 处理</a>现在在所有 schema 类型中保持统一，使数据转换更可预测。新的 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#url-utilities">URL 工具函数</a>支持自定义 URL 构造和搜索参数编码。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">extends</span><span class="token class-name" style="color:rgb(255, 203, 107)"> RestGenerics </span><span class="token class-name operator" style="color:rgb(137, 221, 255)">=</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name builtin" style="color:rgb(130, 170, 255)">any</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">searchToString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">searchParams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use qs library for complex nested object encoding</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> qs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">searchParams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<center><a class="button button--secondary" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#migration-guide">迁移指南</a></center>
<p><strong>破坏性变更：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#null-consistency">Array/Object schema 中保留 null 值</a></li>
</ul>
<p><strong>其他改进：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#searchtostring">RestEndpoint.searchToString()</a> 用于自定义搜索参数编码</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#url-utilities">导出 getUrlBase、getUrlTokens</a> 用于自定义 URL 构造</li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#devtools-fix">修复 DevToolsManager 内存泄漏</a></li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="null-consistency">一致的 null 处理<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#null-consistency" class="hash-link" aria-label="一致的 null 处理的直接链接" title="一致的 null 处理的直接链接" translate="no">​</a></h2>
<p><code>null</code> 值现在在所有 schema 类型中都会被一致地保留。之前，<code>[]</code> 简写和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Array">schema.Array</a>
在遇到 <code>null</code> 值时的行为并不相同。<a href="https://github.com/reactive/data-client/pull/2912" target="_blank" rel="noopener noreferrer" class="">#2912</a></p>
<ul>
<li class=""><code>[]</code> 和 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Array">schema.Array</a> 现在行为完全一致</li>
<li class=""><code>null</code> 值在所有地方都会被保留（在<a class="" href="https://dataclient.io/zh-Hans/rest/guides/relational-data#nesting">嵌套 Entity</a> 中原本就会保留）</li>
<li class=""><code>undefined</code> 值仍然会被过滤掉</li>
</ul>
<p>对于那些显式返回 <code>null</code> 表示数据不存在、而用 <code>undefined</code> 表示字段缺失的 API，这一变更确保了更可预测的行为。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="url-utilities">URL 工具函数<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#url-utilities" class="hash-link" aria-label="URL 工具函数的直接链接" title="URL 工具函数的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="searchtostring">RestEndpoint.searchToString()<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#searchtostring" class="hash-link" aria-label="RestEndpoint.searchToString()的直接链接" title="RestEndpoint.searchToString()的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#searchToString">RestEndpoint.searchToString()</a> 支持对搜索参数进行自定义编码。这对于期望在查询字符串中接收复杂嵌套对象的 API 尤其有用。
<a href="https://github.com/reactive/data-client/pull/2919" target="_blank" rel="noopener noreferrer" class="">#2919</a></p>
<p>例如，使用 <a href="https://github.com/ljharb/qs" target="_blank" rel="noopener noreferrer" class="">qs</a> 库来编码复杂对象：</p>
<div class="language-typescript codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-typescript codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestGenerics </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> qs </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'qs'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">extends</span><span class="token class-name" style="color:rgb(255, 203, 107)"> RestGenerics </span><span class="token class-name operator" style="color:rgb(137, 221, 255)">=</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name builtin" style="color:rgb(130, 170, 255)">any</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">searchToString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">searchParams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> qs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">stringify</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">searchParams</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="geturlbase">getUrlBase、getUrlTokens<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#geturlbase" class="hash-link" aria-label="getUrlBase、getUrlTokens的直接链接" title="getUrlBase、getUrlTokens的直接链接" translate="no">​</a></h3>
<p>新导出的 <code>getUrlBase</code> 和 <code>getUrlTokens</code> 为自定义
<a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#url">RestEndpoint.url()</a> 实现提供了基础构件。
<a href="https://github.com/reactive/data-client/pull/2919" target="_blank" rel="noopener noreferrer" class="">#2919</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getUrlBase</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> getUrlTokens </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Parse path tokens for custom URL logic</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> tokens </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getUrlTokens</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id/posts/:postId'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// =&gt; ['id', 'postId']</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Get base URL without path parameters</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> base </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getUrlBase</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// =&gt; '/users/'</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="devtools-fix">DevToolsManager 内存修复<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#devtools-fix" class="hash-link" aria-label="DevToolsManager 内存修复的直接链接" title="DevToolsManager 内存修复的直接链接" translate="no">​</a></h2>
<p>DevToolsManager 的 action 缓冲区现在限制为 100 条，防止长时间运行或频繁更新的应用出现内存泄漏。<a href="https://github.com/reactive/data-client/commit/4e6a39ea2bfdb1390051f12781e899488609e1a8" target="_blank" rel="noopener noreferrer" class=""><code>4e6a39e</code></a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.10.0 @data-client/rest@^0.10.0 @data-client/test@^0.10.0 @data-client/img@^0.10.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.10.0 @data-client/rest@^0.10.0 @data-client/test@^0.10.0 @data-client/img@^0.10.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.10.0 @data-client/rest@^0.10.0 @data-client/test@^0.10.0 @data-client/img@^0.10.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.10.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.10.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.10.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.10.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="null-arrays">数组中的 null 值<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#null-arrays" class="hash-link" aria-label="数组中的 null 值的直接链接" title="数组中的 null 值的直接链接" translate="no">​</a></h3>
<p>如果你的代码依赖于 <code>null</code> 值被从数组中过滤掉，现在需要显式处理：</p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUsers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Array</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// API response: [{ id: '1' }, null, { id: '2' }]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> usersWithoutNull </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUsers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Entity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">User</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  id </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  name </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">this</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> getUsers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">schema</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Array</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// API response: [{ id: '1' }, null, { id: '2' }]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> usersWithoutNull </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useSuspense</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getUsers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">filter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Boolean</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<p>这一变更与<a class="" href="https://dataclient.io/zh-Hans/rest/guides/relational-data#nesting">嵌套 Entity</a> 原有的 <code>null</code> 处理方式保持一致，使所有 schema 类型的行为统一。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2024/02/15/v0.10-null-consistency-url-utilities#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如往常，如果你遇到任何问题或有疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>REST</category>
            <category>Endpoint</category>
            <category>Schema</category>
        </item>
        <item>
            <title><![CDATA[v0.9：DevTools、Resource.extend 与清理遗留 API]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement</link>
            <guid>https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement</guid>
            <pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Data Client 0.9 带来了更好的 DevTools 体验、用于自定义的 Resource.extend()、新的 controller 方法，并移除了遗留 API，让库更简洁、更快。]]></description>
            <content:encoded><![CDATA[<p>本次发布聚焦于开发者体验：在开发模式下显示的 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#devtools-button">devtools 按钮</a>、更好的 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#devtools-improvements">DevTools 历史记录</a>，以及
<a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#controllerexpireall">controller.expireAll()</a> 和 <a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#controllerfetchifstale">controller.fetchIfStale()</a> 等新的 controller 方法。</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#extend">Resource.extend()</a> 提供了三种强大的方式来自定义 resource——添加新的 endpoint、覆盖已有的 endpoint，或从基础 endpoint 派生。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> UserResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'current'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/current'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<center><a class="button button--secondary" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#migration-guide">迁移指南</a></center>
<p><strong>破坏性变更：</strong></p>
<ul>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#remove-next-exports">移除所有 /next 导出</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#makecacheprovider-removed">移除 makeCacheProvider</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#delete-invalidate">DELETE -&gt; INVALIDATE action 类型</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#legacy-schema-support-dropped">不再支持遗留 schema</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#schema-serializers">Schema 序列化器必须支持函数调用</a></li>
<li class=""><a class="" href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#action-types-prefix">Action 类型加上 'rdc' 前缀</a></li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="resourceextend">Resource.extend() <small>（自 0.5 起）</small><a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#resourceextend" class="hash-link" aria-label="resourceextend的直接链接" title="resourceextend的直接链接" translate="no">​</a></h2>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#extend">Resource.extend()</a> 提供了三种强大的方式来自定义 resource。
<a href="https://github.com/reactive/data-client/commit/51b4b0d188" target="_blank" rel="noopener noreferrer" class="">51b4b0d</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="add-new-endpoints">添加新的 endpoint<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#add-new-endpoints" class="hash-link" aria-label="添加新的 endpoint的直接链接" title="添加新的 endpoint的直接链接" translate="no">​</a></h3>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> UserResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> User</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'current'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/users/current'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="override-existing-endpoints">覆盖已有的 endpoint<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#override-existing-endpoints" class="hash-link" aria-label="覆盖已有的 endpoint的直接链接" title="覆盖已有的 endpoint的直接链接" translate="no">​</a></h3>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> CachedArticleResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  getList</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    dataExpiryLength</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">60</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// 10 minutes</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="derive-from-base-endpoints">从基础 endpoint 派生<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#derive-from-base-endpoints" class="hash-link" aria-label="从基础 endpoint 派生的直接链接" title="从基础 endpoint 派生的直接链接" translate="no">​</a></h3>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> IssueResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/issues/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Issue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Base </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  byRepo</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Base</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">extend</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/repos/:owner/:repo/issues'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="controller-methods">Controller 方法<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#controller-methods" class="hash-link" aria-label="Controller 方法的直接链接" title="Controller 方法的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="controllerexpireall">controller.expireAll() <small>（自 0.3 起）</small><a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#controllerexpireall" class="hash-link" aria-label="controllerexpireall的直接链接" title="controllerexpireall的直接链接" translate="no">​</a></h3>
<p>将所有匹配的响应标记为<em>过时</em>，在继续显示现有数据的同时触发后台重新获取。
<a href="https://github.com/reactive/data-client/pull/2802" target="_blank" rel="noopener noreferrer" class="">#2802</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Mark all article lists as stale - they'll refetch when rendered</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">expireAll</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ArticleResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>这与会完全移除数据的 <code>invalidateAll()</code> 不同。<code>expireAll()</code> 会继续显示缓存的数据，同时在后台获取最新数据。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="controllerfetchifstale">controller.fetchIfStale() <small>（自 0.4 起）</small><a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#controllerfetchifstale" class="hash-link" aria-label="controllerfetchifstale的直接链接" title="controllerfetchifstale的直接链接" translate="no">​</a></h3>
<p>仅在数据被视为过时时才发起获取；否则返回缓存的数据。
<a href="https://github.com/reactive/data-client/pull/2804" target="_blank" rel="noopener noreferrer" class="">#2804</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Perfect for prefetching - won't overfetch fresh data</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">resolveData</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> owner</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> repo </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetchIfStale</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">IssueResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> owner</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> repo </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="devtools-improvements">DevTools 改进<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#devtools-improvements" class="hash-link" aria-label="DevTools 改进的直接链接" title="DevTools 改进的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="devtools-button">DevTools 按钮<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#devtools-button" class="hash-link" aria-label="DevTools 按钮的直接链接" title="DevTools 按钮的直接链接" translate="no">​</a></h3>
<p>开发模式下现在会显示一个浮动按钮，用于快速打开 Redux DevTools 扩展。
<a href="https://github.com/reactive/data-client/pull/2803" target="_blank" rel="noopener noreferrer" class="">#2803</a></p>
<p>通过 <code>devButton</code> prop 配置或禁用它：</p>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Disable the button</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">devButton</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript keyword" style="color:rgb(255, 85, 114);font-style:italic">null</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">App</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Position it differently</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">devButton</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">top-right</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text">  </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">App</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain-text"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag class-name" style="color:rgb(255, 203, 107)">CacheProvider</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="persistent-history">持久化的历史记录<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#persistent-history" class="hash-link" aria-label="持久化的历史记录的直接链接" title="持久化的历史记录的直接链接" translate="no">​</a></h3>
<p>即使页面加载时 DevTools 未打开，也不再丢失历史记录。
<a href="https://github.com/reactive/data-client/commit/2d2e94126e" target="_blank" rel="noopener noreferrer" class="">2d2e941</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="better-state-tracking">更好的状态跟踪<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#better-state-tracking" class="hash-link" aria-label="更好的状态跟踪的直接链接" title="更好的状态跟踪的直接链接" translate="no">​</a></h3>
<p>由于 React 18 会对更新进行批处理，真实状态有时会由多个 action 一起更新。当 devtools 打开时，一个影子状态会准确反映每个 action 带来的变化，便于调试。
<a href="https://github.com/reactive/data-client/commit/c9ca31f3f4" target="_blank" rel="noopener noreferrer" class="">c9ca31f</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="endpoint-properties-visible">Endpoint 属性可见<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#endpoint-properties-visible" class="hash-link" aria-label="Endpoint 属性可见的直接链接" title="Endpoint 属性可见的直接链接" translate="no">​</a></h3>
<p>Endpoint 的属性现在可以在 devtool 检查器中完整查看。
<a href="https://github.com/reactive/data-client/commit/a7da00e82d" target="_blank" rel="noopener noreferrer" class="">a7da00e</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="collection-enhancements">Collection 增强<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#collection-enhancements" class="hash-link" aria-label="Collection 增强的直接链接" title="Collection 增强的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="formdataargumentfiltering">FormData 参数筛选 <small>（自 0.4 起）</small><a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#formdataargumentfiltering" class="hash-link" aria-label="formdataargumentfiltering的直接链接" title="formdataargumentfiltering的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 现在可以基于 FormData 参数进行筛选。<a href="https://github.com/reactive/data-client/commit/f95dbc64d1" target="_blank" rel="noopener noreferrer" class="">f95dbc6</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">getPosts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">push</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> group</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'react'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FormData</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">currentTarget</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>如果 FormData 中包含 <code>author</code> 字段，新创建的条目会被正确地添加到按该作者筛选的 collection 中。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="paginationfield">paginationField <small>（自 0.7 起）</small><a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#paginationfield" class="hash-link" aria-label="paginationfield的直接链接" title="paginationfield的直接链接" translate="no">​</a></h3>
<p>使用 <a class="" href="https://dataclient.io/zh-Hans/rest/api/RestEndpoint#paginationfield">paginationField</a> 轻松支持分页。
<a href="https://github.com/reactive/data-client/commit/c8c5575e5a" target="_blank" rel="noopener noreferrer" class="">c8c557</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  paginationField</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'page'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Fetches page 2 and appends to the collection</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">getPage</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> page</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'2'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="other-improvements">其他改进<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#other-improvements" class="hash-link" aria-label="其他改进的直接链接" title="其他改进的直接链接" translate="no">​</a></h2>
<ul>
<li class="">为 ErrorBoundary 添加 <code>className</code>，为 <a class="" href="https://dataclient.io/zh-Hans/docs/api/AsyncBoundary">AsyncBoundary</a> 添加 <code>errorClassName</code> <a href="https://github.com/reactive/data-client/pull/2785" target="_blank" rel="noopener noreferrer" class="">#2785</a></li>
<li class="">新增 <code>getDefaultManagers()</code> 导出，用于显式控制 manager <a href="https://github.com/reactive/data-client/pull/2791" target="_blank" rel="noopener noreferrer" class="">#2791</a></li>
<li class="">用 UniversalSuspense + BackupLoading 取代 BackupBoundary <a href="https://github.com/reactive/data-client/pull/2803" target="_blank" rel="noopener noreferrer" class="">#2803</a></li>
<li class="">Entity.process() 的第四个参数接收 endpoint 的 <code>args</code> <em>（自 0.7 起）</em> <a href="https://github.com/reactive/data-client/commit/a8936f5e6d" target="_blank" rel="noopener noreferrer" class="">a8936f5</a></li>
<li class="">Collection 新增 <code>nonFilterArgumentKeys</code>，用于在筛选时排除 sort/order 参数 <em>（自 0.7 起）</em> <a href="https://github.com/reactive/data-client/commit/318df89bf7" target="_blank" rel="noopener noreferrer" class="">318df89</a></li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="migration-guide">迁移指南<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#migration-guide" class="hash-link" aria-label="迁移指南的直接链接" title="迁移指南的直接链接" translate="no">​</a></h2>
<p>本次升级需要同时更新所有包的版本。</p>
<div class="theme-tabs-container tabs-container tabList_J5MA"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_l0OV tabs__item--active">NPM</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">Yarn</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">pnpm</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_l0OV">esm.sh</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_wHwb"><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/react@^0.9.0 @data-client/rest@^0.9.0 @data-client/test@^0.9.0 @data-client/img@^0.9.0 @data-client/hooks@^0.9.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">yarn</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.9.0 @data-client/rest@^0.9.0 @data-client/test@^0.9.0 @data-client/img@^0.9.0 @data-client/hooks@^0.9.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">pnpm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">add</span><span class="token plain"> @data-client/react@^0.9.0 @data-client/rest@^0.9.0 @data-client/test@^0.9.0 @data-client/img@^0.9.0 @data-client/hooks@^0.9.0</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div></div><div role="tabpanel" class="tabItem_wHwb" hidden=""><div class="language-html codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-html codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">importmap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript string-property property">"imports"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/react"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/react@^0.9.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/rest"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/rest@^0.9.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/test"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/test@^0.9.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/img"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/img@^0.9.0"</span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">    </span><span class="token script language-javascript string-property property">"@data-client/hooks"</span><span class="token script language-javascript operator" style="color:rgb(137, 221, 255)">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:rgb(195, 232, 141)">"https://esm.sh/@data-client/hooks@^0.9.0"</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">script</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><br></div></code></pre></div></div></div></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="remove-next-exports">移除 /next 导出<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#remove-next-exports" class="hash-link" aria-label="移除 /next 导出的直接链接" title="移除 /next 导出的直接链接" translate="no">​</a></h3>
<p>所有 <code>/next</code> 子路径导出都已移除。之前位于 <code>/next</code> 中的功能现在是标准导出。<a href="https://github.com/reactive/data-client/commit/f65cf832f0" target="_blank" rel="noopener noreferrer" class="">f65cf83</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/next'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="makecacheprovider-removed">移除 makeCacheProvider<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#makecacheprovider-removed" class="hash-link" aria-label="移除 makeCacheProvider的直接链接" title="移除 makeCacheProvider的直接链接" translate="no">​</a></h3>
<p>请直接把 provider 组件传给 makeRenderDataClient。
<a href="https://github.com/reactive/data-client/pull/2787" target="_blank" rel="noopener noreferrer" class="">#2787</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> makeCacheProvider </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> renderDataClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">makeRenderDataClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">makeCacheProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-tsx codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-tsx codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">CacheProvider</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> renderDataClient </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">makeRenderDataClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">CacheProvider</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="delete-invalidate">DELETE -&gt; INVALIDATE action 类型<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#delete-invalidate" class="hash-link" aria-label="DELETE -> INVALIDATE action 类型的直接链接" title="DELETE -> INVALIDATE action 类型的直接链接" translate="no">​</a></h3>
<p>为了更清晰，DELETE action 类型已重命名为 INVALIDATE。
<a href="https://github.com/reactive/data-client/pull/2784" target="_blank" rel="noopener noreferrer" class="">#2784</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">DELETE_TYPE</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">INVALIDATE_TYPE</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="legacy-schema-support-dropped">不再支持遗留 schema<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#legacy-schema-support-dropped" class="hash-link" aria-label="不再支持遗留 schema的直接链接" title="不再支持遗留 schema的直接链接" translate="no">​</a></h3>
<p>对遗留 schema 的所有支持都已移除。请确保你使用的是当前的
Entity 类。<a href="https://github.com/reactive/data-client/pull/2784" target="_blank" rel="noopener noreferrer" class="">#2784</a></p>
<ul>
<li class="">移除了 <code>entity.expiresAt</code></li>
<li class="">移除了所有为向后兼容而保留的 Entity 覆盖</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="schema-serializers">Schema 序列化器必须支持函数调用<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#schema-serializers" class="hash-link" aria-label="Schema 序列化器必须支持函数调用的直接链接" title="Schema 序列化器必须支持函数调用的直接链接" translate="no">​</a></h3>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/guides/network-transform#deserializing-fields">Schema 序列化器</a>现在必须支持函数调用。<code>Date</code> 不再能直接使用。<a href="https://github.com/reactive/data-client/pull/2795" target="_blank" rel="noopener noreferrer" class="">#2795</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  createdAt </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    createdAt</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  createdAt </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">createdAt</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">iso</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">new</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Date</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">iso</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<p>或者，使用 Temporal：</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> Temporal </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'temporal-polyfill'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">MyEntity</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Entity</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  createdAt </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> Temporal</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Instant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fromEpochSeconds</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> schema </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    createdAt</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Temporal</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Instant</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">from</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="action-types-prefix">Action 类型加上 'rdc' 前缀<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#action-types-prefix" class="hash-link" aria-label="Action 类型加上 'rdc' 前缀的直接链接" title="Action 类型加上 'rdc' 前缀的直接链接" translate="no">​</a></h3>
<p>为了更好的命名空间隔离，所有 action 类型现在都带有 'rdc' 前缀。
<a href="https://github.com/reactive/data-client/pull/2781" target="_blank" rel="noopener noreferrer" class="">#2781</a></p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="receive---set-action-names">receive -&gt; set action 名称<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#receive---set-action-names" class="hash-link" aria-label="receive -> set action 名称的直接链接" title="receive -> set action 名称的直接链接" translate="no">​</a></h3>
<p>所有 'receive' action 名称都已重命名为 'set'。
<a href="https://github.com/reactive/data-client/pull/2782" target="_blank" rel="noopener noreferrer" class="">#2782</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> ReceiveAction</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">RECEIVE_TYPE</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">receive</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">endpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> SetAction</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token constant" style="color:rgb(130, 170, 255)">SET_TYPE</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">set</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">endpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="middleware-api-simplified">简化的 Middleware API<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#middleware-api-simplified" class="hash-link" aria-label="简化的 Middleware API的直接链接" title="简化的 Middleware API的直接链接" translate="no">​</a></h3>
<p>Middleware 不再以解构属性的形式接收 <code>controller</code>，而是直接接收 controller。<a href="https://github.com/reactive/data-client/pull/2786" target="_blank" rel="noopener noreferrer" class="">#2786</a></p>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> controller </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'before'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'after'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LoggingManager</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">implements</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">Manager</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line theme-code-block-highlighted-line" style="color:#bfc7d5"><span class="token plain">  getMiddleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Middleware </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> controller </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> next </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> action </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'before'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">next</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">'after'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> action</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> controller</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getState</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">cleanup</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="getdefaultmanagers">getDefaultManagers()<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#getdefaultmanagers" class="hash-link" aria-label="getDefaultManagers()的直接链接" title="getDefaultManagers()的直接链接" translate="no">​</a></h3>
<p>CacheProvider 元素不再共享默认的 manager。请使用 <code>getDefaultManagers()</code> 进行显式控制。
<a href="https://github.com/reactive/data-client/pull/2791" target="_blank" rel="noopener noreferrer" class="">#2791</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> CacheProvider </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> managers </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getDefaultManagers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">CacheProvider managers</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain">managers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">App </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain">CacheProvider</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2024/01/15/v0.9-release-announcement#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如往常，如果你遇到任何问题或有疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>REST</category>
            <category>Resource</category>
            <category>Endpoint</category>
        </item>
        <item>
            <title><![CDATA[v0.2 Controller.fetch、异步 getHeaders、Collection]]></title>
            <link>https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement</link>
            <guid>https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement</guid>
            <pubDate>Tue, 04 Jul 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Data Client 0.2 让列表变更变得简单得多，因为 Collection schema 现在是 Resource 的默认 schema]]></description>
            <content:encoded><![CDATA[<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 让数组和对象可以通过 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#push">push</a> 或 <a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection#unshift">unshift</a>
新成员来轻松扩展。它的名字来自 <a href="https://backbonejs.org/#Collection" target="_blank" rel="noopener noreferrer" class="">Backbone Collections</a>。</p>
<p><a class="" href="https://dataclient.io/zh-Hans/rest/api/Collection">Collection</a> 现在是 <a class="" href="https://dataclient.io/zh-Hans/rest/api/resource#getlist">Resource.getList</a> 的默认 schema。</p>
<div data-playground="true" class="playgroundQueryContainer_vBqa"><div class="playgroundContainer_sLUA row_YGZs"><div class="playgroundTextEdit_rt2K withCover_yq1Z"><div class="editorBody_JtfR"><div class="editorDocs_INVk"><div class="playgroundHeader_Zx4K noupper_WDCF tabControls_trxh"><div class="tabs_m54V" role="tablist" aria-orientation="horizontal"><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">TodoResource</div><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">TodoItem</div><div role="tab" aria-selected="true" tabindex="0" class="tab_bTGw selected_QXZk">CreateTodo</div><div role="tab" aria-selected="false" tabindex="-1" class="tab_bTGw">TodoList</div></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div><div class="playgroundEditor_lYwu"><div><pre class="prism-code language-tsx" style="margin:0;outline:none;padding:10px;font-family:inherit;color:#bfc7d5;background-color:transparent" spellcheck="false"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> useController </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token imports"> </span><span class="token imports maybe-class-name">TodoResource</span><span class="token imports"> </span><span class="token imports punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'./TodoResource'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5">
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">function</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CreateTodo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> userId</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">number</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ctrl </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">useController</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">handleKeyDown</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> e </span><span class="token arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">key</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">===</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'Enter'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token maybe-class-name">TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">getList</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">push</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        userId</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        title</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">currentTarget</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token known-class-name class-name" style="color:rgb(255, 203, 107)">Math</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">random</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">currentTarget</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token property-access">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">''</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">className</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">listItem nogap</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">label</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">input</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">checkbox</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">name</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">new</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">checked</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript boolean" style="color:rgb(255, 88, 116)">false</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">disabled</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">        </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;</span><span class="token tag" style="color:rgb(255, 85, 114)">input</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">type</span><span class="token tag attr-value punctuation attr-equals" style="color:rgb(199, 146, 234)">=</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag attr-value" style="color:rgb(255, 85, 114)">text</span><span class="token tag attr-value punctuation" style="color:rgb(199, 146, 234)">"</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag attr-name" style="color:rgb(255, 203, 107)">onKeyDown</span><span class="token tag script language-javascript script-punctuation punctuation" style="color:rgb(199, 146, 234)">=</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token tag script language-javascript" style="color:rgb(255, 85, 114)">handleKeyDown</span><span class="token tag script language-javascript punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token tag" style="color:rgb(255, 85, 114)"> </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">/&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">      </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">label</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain-text"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain-text">    </span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&lt;/</span><span class="token tag" style="color:rgb(255, 85, 114)">div</span><span class="token tag punctuation" style="color:rgb(199, 146, 234)">&gt;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span>
</span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span>
</span></pre></div></div><div class="playgroundEditor_lYwu hidden_Hh8i"></div></div><div class="storeHost_N0SU"></div><button type="button" class="clean-btn swap_P7aB storeBadge_yrOO" title="显示 Store" aria-pressed="false" data-store-toggle="true"><span aria-hidden="false"><span class="storeBadgeDot_pVWi"></span>Store</span><span aria-hidden="true"><svg class="storeBadgeCode_DfYa" viewBox="0 0 24 24" width="1.15em" height="1.15em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 7-5 5 5 5M16 7l5 5-5 5M14 4l-4 16"></path></svg>代码</span></button></div></div><div class="previewWrapper_edd2"><div class="playgroundHeader_Zx4K previewHeader_MW_M"><span class="liveLabel_MHnJ"><span class="liveLabelText_k6qc">实时预览</span></span><span class="routerSlot_CTii"></span><span class="previewControls_oxCt"><button type="button" class="clean-btn headerButton_h2KM fixturesToggle_OTR0" title="Fixtures" aria-label="Fixtures" aria-expanded="false" aria-controls="_R_22qllq9_"><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 20V4"></path><path d="m3 8 4-4 4 4"></path><path d="M17 4v16"></path><path d="m21 16-4 4-4-4"></path></svg></button><button type="button" class="clean-btn headerButton_h2KM storeHeaderToggle_ToEw" title="显示 Store" aria-label="Store" aria-pressed="false" data-store-toggle="true" disabled=""><svg viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="5" rx="8" ry="3"></ellipse><path d="M4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5"></path><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"></path></svg></button></span></div><div class="fixturesAnchor_fieO"><div id="_R_22qllq9_" class="fixturesPopover_bQwj"><div class="fixtureBlock_mpRK"><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/users</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ (await UserResource.getList(...args)).slice(0, 3)</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">GET</span><span class="fixturePath_Tuwy">/todos</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ (await TodoResource.getList(...args)).slice(0, 7)</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">PATCH</span><span class="fixturePath_Tuwy">/todos/:id</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ { ...(await TodoResource.partialUpdate(...args)), id: args?.[0]?.id }</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div><div class="fixture_Arp7"><button type="button" class="clean-btn fixtureToggle_W1bY" aria-expanded="false"><span class="arrow_tivA right_vs_C" aria-hidden="true">▶</span><span class="method_pU0d">POST</span><span class="fixturePath_Tuwy">/todos</span><span class="fixtureHint_J1_b" aria-hidden="true"><span class="fixtureFn_HVDB">ƒ</span> <!-- -->→ { ...(await TodoResource.getList.push(...args)), id: randomId() }</span></button><div class="unfold_Z0ry" inert="" aria-hidden="true"><div class="unfoldBody_qH0e"></div></div></div></div></div></div><div class="playgroundResult_tefG"><div class="playgroundPreview_rk9R"></div></div></div></div></div>
<p>升级相当简单，因为我们引入了 <code>@data-client/rest/next</code> 和 <code>@data-client/react/next</code>，以便渐进式地采用本版本中变更的新 API。这使得实际的升级只是简单地重命名一下导入路径。</p>
<p>其他亮点包括</p>
<ul>
<li class=""><code>@data-client/rest</code>
<ul>
<li class=""><a href="https://github.com/reactive/data-client/pull/2542" target="_blank" rel="noopener noreferrer" class="">异步 RestEndpoint.getHeaders</a></li>
</ul>
</li>
<li class=""><code>@data-client/react</code>
<ul>
<li class=""><a href="https://github.com/reactive/data-client/pull/2545" target="_blank" rel="noopener noreferrer" class="">Controller.fetch() 的返回值按 schema 反规范化</a></li>
<li class=""><a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">Manager action 类型更新</a></li>
</ul>
</li>
</ul>
<p>完整细节请<a class="" href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#data-clientreact-02">继续阅读</a>：</p>
<!-- -->
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="data-clientreact-02">@data-client/react 0.2<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#data-clientreact-02" class="hash-link" aria-label="@data-client/react 0.2的直接链接" title="@data-client/react 0.2的直接链接" translate="no">​</a></h3>
<p><a href="https://github.com/reactive/data-client/releases/tag/%40data-client%2Freact%400.2.0" target="_blank" rel="noopener noreferrer" class="">https://github.com/reactive/data-client/releases/tag/%40data-client%2Freact%400.2.0</a></p>
<p>升级可以逐步进行，因为所有变更最初都发布在 <code>/next</code> 中。</p>
<ol>
<li class="">
<p>通过从 <code>/next</code> 导入，逐步迁移到新版本</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/react/next'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>升级到 v0.2 - v0.4（全部兼容）。</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/rest@0.4.3</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
</li>
<li class="">
<p>升级后可以逐步更新导入。<code>/next</code> 导出的内容与顶层相同。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> useController </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
</li>
</ol>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="changes">变更<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#changes" class="hash-link" aria-label="变更的直接链接" title="变更的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p><strong>Controller.fetch()</strong>：<a href="https://github.com/reactive/data-client/pull/2545" target="_blank" rel="noopener noreferrer" class="">2545</a> 当 Endpoint 有 Schema 时，Controller.fetch() 返回反规范化后的形式</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token function-variable function" style="color:rgb(130, 170, 255)">handleChange</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> e </span><span class="token operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> todo </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> ctrl</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">fetch</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    TodoResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">partialUpdate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> id</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">id </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> completed</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">currentTarget</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">checked </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// todo is Todo, we can use all its members and be type-safe</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token builtin" style="color:rgb(130, 170, 255)">console</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">log</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">pk</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">title</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>NetworkManager</strong>：NetworkManager 接口改为只支持新的 action <a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a></p>
</li>
<li class="">
<p><strong>SubscriptionManager/PollingSubscription</strong> 接口基于新的 action 进行了简化 <a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a></p>
</li>
</ul>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="removals-of-deprecated-items">移除已弃用项<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#removals-of-deprecated-items" class="hash-link" aria-label="移除已弃用项的直接链接" title="移除已弃用项的直接链接" translate="no">​</a></h4>
<ul>
<li class=""><a href="https://github.com/reactive/data-client/pull/2691" target="_blank" rel="noopener noreferrer" class="">2691</a>：移除 DispatchContext、DenormalizeCacheContext</li>
</ul>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="deprecations">弃用<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#deprecations" class="hash-link" aria-label="弃用的直接链接" title="弃用的直接链接" translate="no">​</a></h4>
<ul>
<li class="">controller.receive、controller.receiveError <a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a></li>
<li class="">RECEIVE_TYPE <a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a></li>
<li class="">MiddlewareAPI.controller（MiddlewareAPI 现在就是 controller 本身）<a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a>
<ul>
<li class=""><code>({controller}) =&gt; {}</code> -&gt; <code>(controller) =&gt; {}</code></li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="data-clientrest-02">@data-client/rest 0.2<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#data-clientrest-02" class="hash-link" aria-label="@data-client/rest 0.2的直接链接" title="@data-client/rest 0.2的直接链接" translate="no">​</a></h3>
<p><a href="https://github.com/reactive/data-client/releases/tag/%40data-client%2Frest%400.2.0" target="_blank" rel="noopener noreferrer" class="">https://github.com/reactive/data-client/releases/tag/%40data-client%2Frest%400.2.0</a></p>
<p>升级可以逐步进行，因为所有变更最初都发布在 <code>/next</code> 中。</p>
<ol>
<li class="">
<p>通过从 <code>/next</code> 导入，逐步<a href="https://github.com/reactive/data-client/pull/2606/files" target="_blank" rel="noopener noreferrer" class="">迁移到新版本</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  GetEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  MutateEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest/next'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>可以参考 /examples 目录的<a href="https://github.com/reactive/data-client/pull/2606/files" target="_blank" rel="noopener noreferrer" class="">迁移</a>作为示例</p>
</li>
<li class="">
<p>升级到 v0.2-0.7（全部兼容）。</p>
<div class="terminal_yWbS"><div class="language-bash codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-bash codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line command_MhHc" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--save</span><span class="token plain"> @data-client/rest@0.7.6</span><br></div></code></pre></div></div><span role="tooltip" class="tip_wqpZ tip_cCYE">在终端中运行</span></div>
</li>
<li class="">
<p>升级后可以逐步更新导入。<code>/next</code> 导出的内容与顶层相同。</p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> RestEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> createResource </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
</li>
</ol>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="changes-1">变更<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#changes-1" class="hash-link" aria-label="变更的直接链接" title="变更的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p>RestEndpoint 的 getRequestInit 和 getHeaders 可以选择返回 promise <a href="https://github.com/reactive/data-client/pull/2542" target="_blank" rel="noopener noreferrer" class="">2542</a></p>
<div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> RestEndpoint </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'@data-client/rest/next'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">default</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AuthdEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)">  </span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">extends</span><span class="token class-name" style="color:rgb(255, 203, 107)"> RestGenerics </span><span class="token class-name operator" style="color:rgb(137, 221, 255)">=</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name builtin" style="color:rgb(130, 170, 255)">any</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)"></span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">declare</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> accessToken</span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getHeaders</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">headers</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> HeadersInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token plain">headers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token string-property property">'Access-Token'</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getOrFetchToken</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">as</span><span class="token plain"> HeadersInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">export</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TodoResource </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">createResource</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  urlPrefix</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'https://jsonplaceholder.typicode.com'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  path</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/todos/:id'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  schema</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> Todo</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  Endpoint</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> AuthdEndpoint</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>破坏性变更：调用 super.getRequestInit() 将返回一个 promise，所以你必须先解析它：</p>
</li>
</ul>
<figure class="figure_HN5N"><div class="grid_iD3H wrap_ES0G"><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">Before</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AuthdEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)">  </span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">extends</span><span class="token class-name" style="color:rgb(255, 203, 107)"> RestGenerics </span><span class="token class-name operator" style="color:rgb(137, 221, 255)">=</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name builtin" style="color:rgb(130, 170, 255)">any</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)"></span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">getRequestInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> RequestInit </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token keyword" style="font-style:italic">super</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getRequestInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      credentials</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'same-origin'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div><div class="language-ts codeBlockContainer_mQmQ theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:transparent"><div class="codeBlockTitle_kY6l">After</div><div class="codeBlockContent_t_Hd"><pre tabindex="0" class="prism-code language-ts codeBlock_RMoD thin-scrollbar" style="color:#bfc7d5;background-color:transparent"><code class="codeBlockLines_AclH"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">AuthdEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)">  </span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name keyword" style="color:rgb(255, 203, 107);font-style:italic">extends</span><span class="token class-name" style="color:rgb(255, 203, 107)"> RestGenerics </span><span class="token class-name operator" style="color:rgb(137, 221, 255)">=</span><span class="token class-name" style="color:rgb(255, 203, 107)"> </span><span class="token class-name builtin" style="color:rgb(130, 170, 255)">any</span><span class="token class-name punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token class-name" style="color:rgb(255, 203, 107)"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token class-name" style="color:rgb(255, 203, 107)"></span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">extends</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">RestEndpoint</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token class-name constant" style="color:rgb(130, 170, 255)">O</span><span class="token class-name operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token keyword" style="font-style:italic">async</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getRequestInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">body</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">any</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">Promise</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">RequestInit</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token operator" style="color:rgb(137, 221, 255)">...</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token keyword" style="font-style:italic">await</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">super</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">getRequestInit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">body</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      credentials</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'same-origin'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></div></code></pre></div></div></div></figure>
<ul>
<li class="">createResource().getList 使用 Collection，.create 会向其追加 <a href="https://github.com/reactive/data-client/pull/2593" target="_blank" rel="noopener noreferrer" class="">2593</a>
<ul>
<li class=""><code>Resource.create</code> 会自动添加到列表中<!-- -->
<ul>
<li class=""><code>Resource.getList.push</code> 与 <code>Resource.create</code> 完全相同</li>
</ul>
</li>
<li class=""><strong>移除</strong>所有 <code>Endpoint.update</code>，因为它不再必要而且不会生效</li>
</ul>
</li>
<li class=""><code>GetEndpoint</code> 和 <code>MutateEndpoint</code> 的参数改为之前 <code>NewGetEndpoint</code>、<code>NewMutateEndpoint</code> 的参数。</li>
<li class="">createResource() 的泛型改为 <code>O extends ResourceGenerics</code>。这允许通过 body 和 searchParams 自定义 Resource 类型 <a href="https://github.com/reactive/data-client/pull/2593" target="_blank" rel="noopener noreferrer" class="">2593</a>
<ul>
<li class=""><code>createGithubResource&lt;U extends string, S extends Schema&gt;</code> -&gt; <code>createGithubResource&lt;O extends ResourceGenerics&gt;</code></li>
</ul>
</li>
</ul>
<p><a href="https://github.com/reactive/data-client/pull/2692" target="_blank" rel="noopener noreferrer" class="">提升 /next 的 PR #2692</a></p>
<h4 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="removals-of-deprecated-items-1">移除已弃用项<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#removals-of-deprecated-items-1" class="hash-link" aria-label="移除已弃用项的直接链接" title="移除已弃用项的直接链接" translate="no">​</a></h4>
<ul>
<li class=""><a href="https://github.com/reactive/data-client/pull/2690" target="_blank" rel="noopener noreferrer" class="">2690</a>：移除已弃用的 <code>Endpoint.optimisticUpdate</code> -&gt; 请使用 <code>Endpoint.getOptimisticResponse</code></li>
<li class=""><a href="https://github.com/reactive/data-client/pull/2688" target="_blank" rel="noopener noreferrer" class="">2688</a> 移除 <code>FetchShape</code> 兼容层。</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_Qii3" id="upgrade-support">升级支持<a href="https://dataclient.io/zh-Hans/blog/2023/07/04/v0.2-release-announcement#upgrade-support" class="hash-link" aria-label="升级支持的直接链接" title="升级支持的直接链接" translate="no">​</a></h3>
<p>一如既往，如果你遇到任何问题或有任何疑问，欢迎加入我们的 <a href="https://discord.gg/wXGV27xm6t" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://img.shields.io/discord/768254430381735967.svg?style=flat-square&amp;colorB=758ED3" alt="Chat" class="img_SS3x"></a> 或<a href="https://github.com/reactive/data-client/issues/new/choose" target="_blank" rel="noopener noreferrer" class="">提交 bug</a></p>]]></content:encoded>
            <category>版本发布</category>
            <category>REST</category>
            <category>Resource</category>
            <category>Endpoint</category>
            <category>Collection</category>
        </item>
    </channel>
</rss>