diff --git a/docs/docs/docs/max/react-query.md b/docs/docs/docs/max/react-query.md index 180ec5932bd1..f9446e00ae40 100644 --- a/docs/docs/docs/max/react-query.md +++ b/docs/docs/docs/max/react-query.md @@ -29,6 +29,14 @@ export default { } ``` +:::info +注:在使用时,请务必检查关于 `refetchOnWindowFocus` 的配置项,详见 [运行时配置项](#运行时配置项) 。 +::: + +## 版本 + +默认使用的是 [TanStack Query](https://tanstack.com/query/latest) v4 版本,若需使用最新 v5 版本,手动安装 v5 版本的 `@tanstack/react-query` 与 `@tanstack/react-query-devtools` 依赖即可。 + ## 特性 插件帮你做了几件事, @@ -66,27 +74,26 @@ export default { - `devtool`:object - `queryClient`: object -比如: +例子: ```ts -const API_SERVER = '/path/to/api/server'; -export const reactQuery = { +// src/app.ts + +import { RuntimeReactQueryType } from 'umi'; + +export const reactQuery: RuntimeReactQueryType = { devtool: { initialIsOpen: true, }, queryClient: { - defaultOptions: { - queries: { - queryFn: async ({ queryKey }) => { - const res = await fetch(`${API_SERVER}/${queryKey.join('/')}`); - if (res.status !== 200) { - throw new Error(res.statusText); - } - return res.json(); - } - } - } + defaultOptions: { + queries: { + // 🟡 此配置具有的表现往往令人出乎意料,若无特殊需求,请默认关闭 + refetchOnWindowFocus: false, + }, + }, }, }; ``` +注:绝大多数项目中,**你都应该默认设定 `refetchOnWindowFocus: false`** ,否则将引发出人意料的反复获取数据效果(这在 SWR 中被称为 [`revalidateOnFocus`](https://swr.vercel.app/zh-CN/docs/api#options) )。 diff --git a/examples/with-react-query-v5/.umirc.ts b/examples/with-react-query-v5/.umirc.ts new file mode 100644 index 000000000000..38a5d9a5a541 --- /dev/null +++ b/examples/with-react-query-v5/.umirc.ts @@ -0,0 +1,4 @@ +export default { + plugins: ['@umijs/plugins/dist/react-query'], + reactQuery: {}, +}; diff --git a/examples/with-react-query-v5/app.ts b/examples/with-react-query-v5/app.ts new file mode 100644 index 000000000000..3dd82a872e80 --- /dev/null +++ b/examples/with-react-query-v5/app.ts @@ -0,0 +1,14 @@ +import { RuntimeReactQueryType } from 'umi'; + +export const reactQuery: RuntimeReactQueryType = { + queryClient: { + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, + }, + devtool: { + buttonPosition: 'bottom-left', + }, +}; diff --git a/examples/with-react-query-v5/package.json b/examples/with-react-query-v5/package.json new file mode 100644 index 000000000000..7dd6b67be53e --- /dev/null +++ b/examples/with-react-query-v5/package.json @@ -0,0 +1,14 @@ +{ + "name": "@example/with-react-query-v5", + "private": true, + "scripts": { + "build": "umi build", + "dev": "umi dev", + "start": "npm run dev" + }, + "dependencies": { + "@tanstack/react-query": "^5.28.6", + "@tanstack/react-query-devtools": "^5.28.6", + "umi": "workspace:*" + } +} diff --git a/examples/with-react-query-v5/pages/index.tsx b/examples/with-react-query-v5/pages/index.tsx new file mode 100644 index 000000000000..df573f5ae6cf --- /dev/null +++ b/examples/with-react-query-v5/pages/index.tsx @@ -0,0 +1,30 @@ +import { useQuery } from 'umi'; +import '../style.less'; + +export default function HomePage() { + const { isFetching, data } = useQuery({ + queryKey: ['repoData'], + queryFn: () => { + return new Promise<{ stargazers_count: number }>((resolve, _) => { + setTimeout(async () => { + const res = await fetch('https://api.github.com/repos/umijs/umi'); + const json = await res.json(); + resolve(json); + }, 500); + }); + }, + }); + + return ( +
+
+

UmiJS x react-query v5

+ {isFetching ? ( +

Loading ...

+ ) : ( +

UmiJS has {data?.stargazers_count} stars now!

+ )} +
+
+ ); +} diff --git a/examples/with-react-query-v5/readme.md b/examples/with-react-query-v5/readme.md new file mode 100644 index 000000000000..cfb2bd497bb8 --- /dev/null +++ b/examples/with-react-query-v5/readme.md @@ -0,0 +1,3 @@ +# react-query-v5 + +An example of using [UmiJS](https://umijs.org/zh-CN) with [react-query](https://github.com/TanStack/query) v5. diff --git a/examples/with-react-query-v5/style.less b/examples/with-react-query-v5/style.less new file mode 100644 index 000000000000..6f08a19486e5 --- /dev/null +++ b/examples/with-react-query-v5/style.less @@ -0,0 +1,22 @@ +body { + font-family: 'Lucida Sans', sans-serif; +} + +.container { + width: 100%; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + + div { + display: flex; + flex-direction: column; + align-items: center; + } + + .title { + font-size: 64px; + } + +} diff --git a/examples/with-react-query-v5/tsconfig.json b/examples/with-react-query-v5/tsconfig.json new file mode 100644 index 000000000000..7fa7937c8056 --- /dev/null +++ b/examples/with-react-query-v5/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.umi/tsconfig.json" +} diff --git a/examples/with-react-query/app.ts b/examples/with-react-query/app.ts new file mode 100644 index 000000000000..7433df6cf8a8 --- /dev/null +++ b/examples/with-react-query/app.ts @@ -0,0 +1,14 @@ +import { RuntimeReactQueryType } from 'umi'; + +export const reactQuery: RuntimeReactQueryType = { + queryClient: { + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, + }, + devtool: { + position: 'bottom-left', + }, +}; diff --git a/examples/with-react-query/pages/index.tsx b/examples/with-react-query/pages/index.tsx index d26d1dc11457..eccf592e95b8 100644 --- a/examples/with-react-query/pages/index.tsx +++ b/examples/with-react-query/pages/index.tsx @@ -2,7 +2,7 @@ import { useQuery } from 'umi'; import '../style.less'; export default function HomePage() { - const { isLoading, data } = useQuery(['repoData'], () => + const { isFetching, data } = useQuery(['repoData'], () => fetch('https://api.github.com/repos/umijs/umi').then((res) => res.json()), ); @@ -10,7 +10,7 @@ export default function HomePage() {

UmiJS x react-query

- {isLoading &&

Loading ...

} + {isFetching &&

Loading ...

} {data &&

UmiJS has {data.stargazers_count} stars now!

}
diff --git a/examples/with-react-query/tsconfig.json b/examples/with-react-query/tsconfig.json new file mode 100644 index 000000000000..7fa7937c8056 --- /dev/null +++ b/examples/with-react-query/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.umi/tsconfig.json" +} diff --git a/packages/plugins/src/layout.ts b/packages/plugins/src/layout.ts index 7fbd6d2c1479..0a711ac4fdfa 100644 --- a/packages/plugins/src/layout.ts +++ b/packages/plugins/src/layout.ts @@ -1,7 +1,8 @@ import { existsSync, readFileSync } from 'fs'; import { dirname, join } from 'path'; import { IApi, RUNTIME_TYPE_FILE_NAME } from 'umi'; -import { lodash, Mustache, NpmClientEnum, winPath } from 'umi/plugin-utils'; +import { lodash, Mustache, winPath } from 'umi/plugin-utils'; +import { isFlattedNodeModulesDir } from './utils/npmClient'; import { resolveProjectDep } from './utils/resolveProjectDep'; import { withTmpPath } from './utils/withTmpPath'; @@ -117,21 +118,10 @@ export default (api: IApi) => { }); api.onGenerateFiles(() => { - let realNpmClient = api.appData.npmClient; - // tnpm 作为 npmClient 时,可能使用不同的安装模式 - if ( - api.appData.npmClient === NpmClientEnum.tnpm && - api.pkg.tnpm?.mode && - [NpmClientEnum.npm, NpmClientEnum.yarn].includes(api.pkg.tnpm.mode) - ) { - realNpmClient = api.pkg.tnpm.mode; - } // use absolute path to types references in `npm/yarn` will cause case problems. // https://github.com/umijs/umi/discussions/10947 // https://github.com/umijs/umi/discussions/11570 - const isFlattedDepsDir = [NpmClientEnum.npm, NpmClientEnum.yarn].includes( - realNpmClient, - ); + const isFlattedDepsDir = isFlattedNodeModulesDir(api); const PKG_TYPE_REFERENCE = ` /// { + let currentNpmClient = api.appData.npmClient; + // tnpm 作为 npmClient 时,可能使用不同的安装模式 + const tnpmCompatMode: string | undefined = + api.appData.npmClient === NpmClientEnum.tnpm && api.pkg.tnpm?.mode; + if (tnpmCompatMode) { + if (FLATTED_NPM_CLIENT.includes(api.pkg.tnpm.mode)) { + return true; + } + } + const isFlattedDir = FLATTED_NPM_CLIENT.includes(currentNpmClient); + return isFlattedDir; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 69ca0c69f4f5..1c04a0388aa9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1423,6 +1423,18 @@ importers: specifier: workspace:* version: link:../../packages/umi + examples/with-react-query-v5: + dependencies: + '@tanstack/react-query': + specifier: ^5.28.6 + version: 5.28.6(react@18.1.0) + '@tanstack/react-query-devtools': + specifier: ^5.28.6 + version: 5.28.6(@tanstack/react-query@5.28.6)(react@18.1.0) + umi: + specifier: workspace:* + version: link:../../packages/umi + examples/with-react-three-fiber: dependencies: '@react-three/drei': @@ -16348,6 +16360,14 @@ packages: /@tanstack/query-core@4.24.10: resolution: {integrity: sha512-2QywqXEAGBIUoTdgn1lAB4/C8QEqwXHj2jrCLeYTk2xVGtLiPEUD8jcMoeB2noclbiW2mMt4+Fq7fZStuz3wAQ==} + /@tanstack/query-core@5.28.6: + resolution: {integrity: sha512-hnhotV+DnQtvtR3jPvbQMPNMW4KEK0J4k7c609zJ8muiNknm+yoDyMHmxTWM5ZnlZpsz0zOxYFr+mzRJNHWJsA==} + dev: false + + /@tanstack/query-devtools@5.28.6: + resolution: {integrity: sha512-DXJGqbrsteWU9XehDf6s3k3QxwQqGUlNXpitsF1xbwkYBcDaAakiC6hjJSMfPBHOrbZCnWfAGCVf4vh2D75/xw==} + dev: false + /@tanstack/react-query-devtools@4.24.10(@tanstack/react-query@4.24.10)(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-1uzJNLdLjRsNt4O5ldv1SYPevWvSdHtKIyVJeUv4hSERPEhrKKfa8WC3dBOX24CdLEYH2ndLZW4ZiC9nzSKCtg==} peerDependencies: @@ -16388,6 +16408,20 @@ packages: use-sync-external-store: 1.2.0(react@18.1.0) dev: false + /@tanstack/react-query-devtools@5.28.6(@tanstack/react-query@5.28.6)(react@18.1.0): + resolution: {integrity: sha512-xSfskHlM2JkP7WpN89UqhJV2RbFxg8YnOMzQz+EEzWSsgxMI5Crce8HO9pcUAcJce8gSmw93RQwuKNdG3FbT6w==} + peerDependencies: + '@tanstack/react-query': ^5.28.6 + react: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + dependencies: + '@tanstack/query-devtools': 5.28.6 + '@tanstack/react-query': 5.28.6(react@18.1.0) + react: 18.1.0 + dev: false + /@tanstack/react-query@4.24.10(react-dom@17.0.2)(react@17.0.2): resolution: {integrity: sha512-FY1DixytOcNNCydPQXLxuKEV7VSST32CAuJ55BjhDNqASnMLZn+6c30yQBMrODjmWMNwzfjMZnq0Vw7C62Fwow==} peerDependencies: @@ -16428,6 +16462,18 @@ packages: use-sync-external-store: 1.2.0(react@18.1.0) dev: false + /@tanstack/react-query@5.28.6(react@18.1.0): + resolution: {integrity: sha512-/DdYuDBSsA21Qbcder1R8Cr/3Nx0ZnA2lgtqKsLMvov8wL4+g0HBz/gWYZPlIsof7iyfQafyhg4wUVUsS3vWZw==} + peerDependencies: + react: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + dependencies: + '@tanstack/query-core': 5.28.6 + react: 18.1.0 + dev: false + /@testing-library/dom@9.0.0: resolution: {integrity: sha512-+/TLgKNFsYUshOY/zXsQOk+PlFQK+eyJ9T13IDVNJEi+M+Un7xlJK+FZKkbGSnf0+7E1G6PlDhkSYQ/GFiruBQ==} engines: {node: '>=14'}