v0.13:NextJS App Router、Expo、React 19、Redux
平台:
测试:
- MockResolver 已标记为 'client' 代码,以适配 NextJS App Router
- 导出 renderDataHook() - 兼容 React 17 和 18
以下包已并入 @data-client/react:
- Redux
- Hooks
其他改进
- 新增 controller.set(Todo, { id }, { id, completed: false })
- RestEndpoint.path 支持 +、* 和 {}
- 修复 Union 在 controller.fetch() 中的返回值
- actionTypes.SET_TYPE -> actionTypes.SET_RESPONSE_TYPE
- SetAction -> SetResponseAction
- 最低 React 版本 16.8.4 -> 16.14
由于发布事故,0.12 版本被跳过了。
平台
NextJS App Router
NextJS 12 引入了在 '/app' 目录中进行路由的新方式。它带来了进一步的性能提升,以及动态路由和嵌套路由。这使 NextJS 成为构建富动态应用的可行平台,而不仅仅是静态网站。
其他获取方式需要缓慢的客户端获取;而 Reactive Data Client 则兼具 SPA 和 MPA 两者的优点。#3074、#3093
与 MPA 一样,使用 Data Client 进行 SSR 意味着最快的首次页面加载。与 SPA 一样,Data Client 提供比 MPA 更快的导航、客户端变更以及远程驱动的变更(例如 websocket)。
此外,搭配 SSR 的 Data Client 相比其他客户端获取库依然保持性能优势。
Data Client 对 HTML 进行流式 SSR,优化了应用的初始加载体验。独特之处在于,Data Client 随后立即可交互,且客户端获取次数为 0。这是通过在 SSR 阶段用规范化数据初始化客户端 Store 来实现的。
用法
在你的根布局中渲染来自 /nextjs 入口的 DataProvider。
import { DataProvider } from '@data-client/react/nextjs';
import { AsyncBoundary } from '@data-client/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
<DataProvider>
<header>Title</header>
<AsyncBoundary>{children}</AsyncBoundary>
<footer></footer>
</DataProvider>
</body>
</html>
);
}
变更演示
探索 nextjs 示例
实时数据演示
其他 SSR
新增 /ssr 入口——完全不再需要 @data-client/ssr 包 d1b9e96
import {
createPersistedStore,
createServerDataComponent,
} from '@data-client/ssr';
import {
createPersistedStore,
createServerDataComponent,
} from '@data-client/react/ssr';
这使得将 Data Client 轻松集成到任何 SSR 框架成为可能。我们欢迎为集成任何开源框架所做的贡献。
Expo
我们已开始着手 Expo/ExpoGo 演示,并借此发现并修复了这些集成中的一些兼容性问题。如果有我们遗漏的问题,请报告给我们。
React 19
我们现在支持 React 19。#3071
这需要放弃对低于 16.14 版本的支持,因为我们必须使用 React 自身导出的 jsx 运行时。这还带来了减小包体积的额外好处。
Redux
新增 @data-client/react/redux #3099。这样就不再需要单独的 @data-client/redux 包。
import {
ExternalDataProvider,
PromiseifyMiddleware,
applyManager,
initialState,
createReducer,
prepareStore,
} from '@data-client/redux';
import {
ExternalDataProvider,
PromiseifyMiddleware,
applyManager,
initialState,
createReducer,
prepareStore,
} from '@data-client/react/redux';
为 prepareStore() 新增 middlewares 参数 #3099
const { store, selector, controller } = prepareStore(
initialState,
managers,
Controller,
otherReducers,
extraMiddlewares,
);
controller.set()
controller.set() 可以更新任意 Queryable Schema。#3105、#3129
ctrl.set(
Todo,
{ id: '5' },
{ id: '5', title: 'tell me friends how great Data Client is' },
);
当需要使用派生数据时,值可以是函数。这能避免竞态条件。
const id = '2';
ctrl.set(Article, { id }, article => ({ id, votes: article.votes + 1 }));
响应必须包含足以计算 Entity.pk() 的值
这让通过 Manager 操作 store 变得更加直接。例如,我们可以在收到 websocket 消息时直接设置 Ticker 实体:
探索 coin-app 示例
类型改进
-
改进 controller 各方法的类型匹配 #3043
-
改进 useFetch() 的参数类型匹配,使其与 useSuspense() 类似 #3043
REST 变更
路径字符串
RestEndpoint.path 支持 +、* 和 {}。a6b4f4a
const getThing = new RestEndpoint({
path: '/:attr1?{-:attr2}?{-:attr3}?',
});
getThing({ attr1: 'hi' });
getThing({ attr2: 'hi' });
getThing({ attr3: 'hi' });
getThing({ attr1: 'hi', attr3: 'ho' });
getThing({ attr2: 'hi', attr3: 'ho' });
ctrl.fetch() 与 Union
ctrl.fetch() 返回值中的 Union 值现在是其 Entity 类的实例。#3063
import { getFeed } from './Feed'; function useFeedHandler() { const ctrl = useController(); const handleSomething = async () => { const feed = await ctrl.fetch(getFeed); return feed.map(item => { if (item.type == 'link') { // we can use class defined getter return item.anchor; } }); } return handleSomething; }
迁移指南
本次升级需要同时更新所有包的版本。
- NPM
- Yarn
- pnpm
- esm.sh
npm install --save @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0
yarn add @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0
pnpm add @data-client/react@^0.13.0 @data-client/rest@^0.13.0 @data-client/test@^0.13.0 @data-client/img@^0.13.0
<script type="importmap">
{
"imports": {
"@data-client/react": "https://esm.sh/@data-client/react@^0.13.0",
"@data-client/rest": "https://esm.sh/@data-client/rest@^0.13.0",
"@data-client/test": "https://esm.sh/@data-client/test@^0.13.0",
"@data-client/img": "https://esm.sh/@data-client/img@^0.13.0"
}
}
</script>
actionTypes.SET_TYPE -> actionTypes.SET_RESPONSE_TYPE
如果你编写了处理 actionTypes.SET_TYPE 的自定义 Manager,需要将其重命名为 actionTypes.SET_RESPONSE_TYPE。
import type { Manager, Middleware } from '@data-client/react';
import { actionTypes } from '@data-client/react';
export default class LoggingManager implements Manager {
middleware: Middleware = controller => next => async action => {
switch (action.type) {
case actionTypes.SET_TYPE:
console.info(
`${action.endpoint.name} ${JSON.stringify(action.response)}`,
);
return next(action);
// actions must be explicitly passed to next middleware
default:
return next(action);
}
};
cleanup() {}
}
import type { Manager, Middleware } from '@data-client/react';
import { actionTypes } from '@data-client/react';
export default class LoggingManager implements Manager {
middleware: Middleware = controller => next => async action => {
switch (action.type) {
case actionTypes.SET_RESPONSE_TYPE:
console.info(
`${action.endpoint.name} ${JSON.stringify(action.response)}`,
);
return next(action);
// actions must be explicitly passed to next middleware
default:
return next(action);
}
};
cleanup() {}
}
SetAction -> SetResponseAction
React 16.14+
将最低 React 版本从 16.8.4 提高到 16.14。无需修改任何代码。
- NPM
- Yarn
- pnpm
- esm.sh
npm install --save react@16.14 react-dom@16.14
yarn add react@16.14 react-dom@16.14
pnpm add react@16.14 react-dom@16.14
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@16.14",
"react-dom": "https://esm.sh/react-dom@16.14"
}
}
</script>
CacheProvider -> DataProvider
迁移到 DataProvider 以兼容未来版本。它同时也以
CacheProvider 的名称导出,因此这不是破坏性变更。#3095
import { CacheProvider } from '@data-client/react';
import ReactDOM from 'react-dom';
ReactDOM.createRoot(document.body)
.render(
<CacheProvider>
<App />
</CacheProvider>,
);
import { DataProvider } from '@data-client/react';
import ReactDOM from 'react-dom';
ReactDOM.createRoot(document.body)
.render(
<DataProvider>
<App />
</DataProvider>,
);
升级支持
一如既往,如果你遇到任何问题或有任何疑问,欢迎加入我们的 或提交 bug
