T
TanStack•4y ago
wise-white

No QueryClient set, use QueryClientProvider to set one (yarn workspaces)

Hello, I've a monorepo build with yarn workspaces, I've a components workspace that contains all my shareables components and another workspace that contain the APP. I've install the react-query library as a dependency in the app workspace and set it up as peer dependency in the component workspace Here is the APP component
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Routes>
<Route path="/" element={<Home />}>
<Route path="dashboard" element={<DashboardPage />} />
{/* TODO: remove builder route here */}
<Route path="builder/content" element={<ContentBuilderPage />} />
<Route path="builder/training" element={<TrainingBuilderPage />} />
<Route
path="forms/renew-sub"
element={<RenewSubscriptionPage email={process.env.REACT_APP_USER_EMAIL || ""} />}
/>
<Route
path="audit"
element={<ClinicalAuditPage sessionUid="ds5q1d5sq15" clinicalAuditMongoId="dsqdsq45154154" />}
/>
<Route path="admin" element={<HelloPage />}>
<Route path="login" element={<Login />} />
<Route path="reset-password" element={<ResetPasswordPage />} />
{/*<Route path="builder/content" element={<ContentBuilderPage/>}/>
<Route path="builder/training" element={<TrainingBuilderPage/>}/>*/}
</Route>
</Route>
</Routes>
</QueryClientProvider>
);
}
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Routes>
<Route path="/" element={<Home />}>
<Route path="dashboard" element={<DashboardPage />} />
{/* TODO: remove builder route here */}
<Route path="builder/content" element={<ContentBuilderPage />} />
<Route path="builder/training" element={<TrainingBuilderPage />} />
<Route
path="forms/renew-sub"
element={<RenewSubscriptionPage email={process.env.REACT_APP_USER_EMAIL || ""} />}
/>
<Route
path="audit"
element={<ClinicalAuditPage sessionUid="ds5q1d5sq15" clinicalAuditMongoId="dsqdsq45154154" />}
/>
<Route path="admin" element={<HelloPage />}>
<Route path="login" element={<Login />} />
<Route path="reset-password" element={<ResetPasswordPage />} />
{/*<Route path="builder/content" element={<ContentBuilderPage/>}/>
<Route path="builder/training" element={<TrainingBuilderPage/>}/>*/}
</Route>
</Route>
</Routes>
</QueryClientProvider>
);
}
And how i'm using useQuery inside the component :
const PatientList: FC = () => {
const { data, status, error } = useQuery({
queryKey: ["userClinicalAudit"],
queryFn: fakeUserClinicalFetch,
});
const handlePatientNameChange = (event: React.ChangeEvent<HTMLInputElement>, patientIndex: number) => {
/*const patients = [...userClinicalAudit.patients!];
patients[patientIndex].name = event.target.value;
setUserClinicalAudit({ ...userClinicalAudit, patients: patients });*/
};

if (status === "loading") {
return <p>Loading...</p>;
}
if (status === "error") {
return <p>Error :(</p>;
}

return (
<Grid2 container spacing={2} rowSpacing={2}>
{data &&
data.data.patients.map((patient: { name: string }, index: number) => (
<Grid2
key={patient.name + "-" + index}
xs={8}
md={6}
lg={3}
xsOffset={2}
mdOffset={3}
lgOffset={0}
display="flex"
justifyContent="center"
alignItems="center"
>
<PatientButton
name={patient.name}
progress={50}
onPatientNameChange={(event: React.ChangeEvent<HTMLInputElement>) =>
handlePatientNameChange(event, index)
}
/>
</Grid2>
))}
</Grid2>
);
};
export default PatientList;
const PatientList: FC = () => {
const { data, status, error } = useQuery({
queryKey: ["userClinicalAudit"],
queryFn: fakeUserClinicalFetch,
});
const handlePatientNameChange = (event: React.ChangeEvent<HTMLInputElement>, patientIndex: number) => {
/*const patients = [...userClinicalAudit.patients!];
patients[patientIndex].name = event.target.value;
setUserClinicalAudit({ ...userClinicalAudit, patients: patients });*/
};

if (status === "loading") {
return <p>Loading...</p>;
}
if (status === "error") {
return <p>Error :(</p>;
}

return (
<Grid2 container spacing={2} rowSpacing={2}>
{data &&
data.data.patients.map((patient: { name: string }, index: number) => (
<Grid2
key={patient.name + "-" + index}
xs={8}
md={6}
lg={3}
xsOffset={2}
mdOffset={3}
lgOffset={0}
display="flex"
justifyContent="center"
alignItems="center"
>
<PatientButton
name={patient.name}
progress={50}
onPatientNameChange={(event: React.ChangeEvent<HTMLInputElement>) =>
handlePatientNameChange(event, index)
}
/>
</Grid2>
))}
</Grid2>
);
};
export default PatientList;
What am I doing wrong ? Thank you
9 Replies
wise-white
wise-whiteOP•4y ago
Here is my APP packages.json
{
"name": "@services/web",
"version": "0.1.0",
"private": true,
"scripts": {
"watch": "BROWSER=none react-scripts start",
"start": "yarn workspaces foreach -pRiv -j unlimited --from '@services/web' run watch",
"local": "cross-env NODE_ENV=development env-cmd -f .env.local yarn start",
"dev": "env-cmd -f .env.dev yarn start",
"build": "rm -rf build && react-scripts build",
"prod": "rm -rf build && env-cmd -f .env.prod react-scripts build",
"test": "echo FIXME react-scripts test"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@packages/components": "workspace:^",
"@packages/platform": "workspace:^",
"@tanstack/react-query": "^4.18.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/testing-library__jest-dom": "^5.14.5",
"axios": "^1.0.0",
"dayjs": "^1.11.5",
"env-cmd": "^10.1.0",
"http-proxy-middleware": "^2.0.6",
"immer": "^9.0.16",
"jose": "^4.10.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6",
"react-scripts": "^5.0.1",
"use-immer": "^0.7.0",
"usehooks-ts": "^2.9.1",
"web-vitals": "^3.0.3"
},
"devDependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.10.6",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"@types/jest": "^29.1.2",
"@types/node": "^18.11.9",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"cross-env": "^7.0.3"
},
"peerDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4"
}
}
{
"name": "@services/web",
"version": "0.1.0",
"private": true,
"scripts": {
"watch": "BROWSER=none react-scripts start",
"start": "yarn workspaces foreach -pRiv -j unlimited --from '@services/web' run watch",
"local": "cross-env NODE_ENV=development env-cmd -f .env.local yarn start",
"dev": "env-cmd -f .env.dev yarn start",
"build": "rm -rf build && react-scripts build",
"prod": "rm -rf build && env-cmd -f .env.prod react-scripts build",
"test": "echo FIXME react-scripts test"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@packages/components": "workspace:^",
"@packages/platform": "workspace:^",
"@tanstack/react-query": "^4.18.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/testing-library__jest-dom": "^5.14.5",
"axios": "^1.0.0",
"dayjs": "^1.11.5",
"env-cmd": "^10.1.0",
"http-proxy-middleware": "^2.0.6",
"immer": "^9.0.16",
"jose": "^4.10.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6",
"react-scripts": "^5.0.1",
"use-immer": "^0.7.0",
"usehooks-ts": "^2.9.1",
"web-vitals": "^3.0.3"
},
"devDependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.10.6",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"@types/jest": "^29.1.2",
"@types/node": "^18.11.9",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"cross-env": "^7.0.3"
},
"peerDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4"
}
}
And here the component workspaces packagae.json
{
"name": "@packages/components",
"version": "1.0.0",
"packageManager": "yarn@3.2.4",
"files": [
"/dist"
],
"scripts": {
"build": "tsc --project ./",
"watch": "tsc --project ./ --watch",
"local": "yarn watch",
"dev": "yarn watch",
"prod": "yarn build"
},
"dependencies": {
"@packages/platform": "workspace:^",
"@tanstack/react-query": "^4.18.0",
"axios": "^1.0.0",
"dayjs": "^1.11.5",
"draft-js": "^0.11.7",
"gsap": "npm:@gsap/shockingly@^3.11.3",
"immer": "^9.0.16",
"react-draft-wysiwyg": "^1.15.0",
"use-immer": "^0.7.0",
"usehooks-ts": "^2.9.1"
},
"peerDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6"
},
"devDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"@types/draft-js": "^0.11.9",
"@types/immutable": "^3.8.7",
"@types/node": "^18.11.9",
"@types/react": "^18.0.21",
"@types/react-draft-wysiwyg": "^1.13.4",
"immutable": "^4.1.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6",
"typescript": "^4.8.4"
}
}
{
"name": "@packages/components",
"version": "1.0.0",
"packageManager": "yarn@3.2.4",
"files": [
"/dist"
],
"scripts": {
"build": "tsc --project ./",
"watch": "tsc --project ./ --watch",
"local": "yarn watch",
"dev": "yarn watch",
"prod": "yarn build"
},
"dependencies": {
"@packages/platform": "workspace:^",
"@tanstack/react-query": "^4.18.0",
"axios": "^1.0.0",
"dayjs": "^1.11.5",
"draft-js": "^0.11.7",
"gsap": "npm:@gsap/shockingly@^3.11.3",
"immer": "^9.0.16",
"react-draft-wysiwyg": "^1.15.0",
"use-immer": "^0.7.0",
"usehooks-ts": "^2.9.1"
},
"peerDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6"
},
"devDependencies": {
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/lab": "^5.0.0-alpha.107",
"@mui/material": "^5.10.13",
"@mui/system": "^5.10.9",
"@mui/x-date-pickers": "^5.0.4",
"@tanstack/react-query": "^4.18.0",
"@types/draft-js": "^0.11.9",
"@types/immutable": "^3.8.7",
"@types/node": "^18.11.9",
"@types/react": "^18.0.21",
"@types/react-draft-wysiwyg": "^1.13.4",
"immutable": "^4.1.0",
"react": "^18.2",
"react-dom": "^18.2",
"react-router-dom": "6",
"typescript": "^4.8.4"
}
}
harsh-harlequin
harsh-harlequin•4y ago
Almost always, it's because you somehow have two versions of react-query around.
rare-sapphire
rare-sapphire•4y ago
@TkDodo 🔮 I have the same problem only my package s do not live in the same repo, they are published on NPM. But since the upgrade to v4 I get the "No QueryClient set" error. I made sure that @tanstack/react-query is a peerDependency. I've been stuck on this for days now. Any idea ?
harsh-harlequin
harsh-harlequin•4y ago
which package manager are you using? I know pnpm has some issues in that regard because I stumbled also: https://github.com/pnpm/pnpm/issues/5351
GitHub
pnpm creates multiple installations for same dependency · Issue #53...
pnpm version: 7.11.0 Code to reproduce the issue: I have a workspace with main app A and a library B. A had react-query as a dependency. B has react-query as a peerDependency. For library B to be a...
rare-sapphire
rare-sapphire•4y ago
@TkDodo 🔮 I use yarn. I made sure that react and react-dom are also in the peerDependencies list, but nothing helped.
foreign-sapphire
foreign-sapphire•3y ago
We're getting this issue too. We can't upgrade past 4.2.3. yarn why shows we only have 1 version of React Query and 1 version of react installed. I wonder if there's some mix of CJS and ESM versions being used or something? Just speculating, not sure I know enough
correct-apricot
correct-apricot•2y ago
Seems the issue persists in v5 of the library. I got a similar issue, where I attempted extracting out a simple hook from a host app into a standalone npm package. And the host app as a result would complain Error: No QueryClient set, use QueryClientProvider to set one. The client is set and wouldn't have such an error when using the host app's local version of the same exact hook. The hook in question is very simple, quite literally:
export const useGetMyAssets = (asset, opts) => {
const url = "<...the API endpoint...>"
return useQuery({
queryKey: ["useGetMyAssets", asset],
queryFn: () => fetch(url).then(r => r.json()),
})
}
export const useGetMyAssets = (asset, opts) => {
const url = "<...the API endpoint...>"
return useQuery({
queryKey: ["useGetMyAssets", asset],
queryFn: () => fetch(url).then(r => r.json()),
})
}
The published package defines a peerDependency with the exact same version "@tanstack/react-query": "^5.45.1" found in the host app's yarn.lock (using yarn classic). Is there any workaround?
harsh-harlequin
harsh-harlequin•2y ago
I can assure you there is no issue in the library. You get this error when you have multiple versions of react-query, so the react context that the provider creates is not the same as the react context that the consumer consumes. It's a bundling / installer / setup issue that you would likely also have with any other library that uses react-context
correct-apricot
correct-apricot•2y ago
The hook which is packaged doesn't bring its own dependency of @tanstack/react-query, but designated only as peerDependency. I worked around this issue through designating the exports definition in package.json, which typically isn't required
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
Granted, this is probably because the involvement of react context as you mentioned. Perhaps a mention in the documentation for such case (covers packaging react-query based hooks as standalone packages, a monorepo/workspace setup, etc), with caveats such as ensuring consistent react-query version, and pay attention to how the esmodules/commonjs exports are handled would be helpful

Did you find this page helpful?