T
TanStack•3y ago
rival-black

Trying to invalidateQueries and then run window.print(), but keep getting outdated data

It turns out this is "kindda doing the trick but not correctly" as if i takes more than 1second... i will get outdated info in the printed sheet. Is there a way to wait for queryClient to finish updating the component and when it finishes, it runs window.pint?
const handleImprimir = async () => {
...code...

await queryClient.invalidateQueries(['invoiceNumber'])

setTimeout(() => {
window.print()
}, 1000)
}
const handleImprimir = async () => {
...code...

await queryClient.invalidateQueries(['invoiceNumber'])

setTimeout(() => {
window.print()
}, 1000)
}
6 Replies
rival-black
rival-black•3y ago
Haven't we talked about this in GitHub discussions already 😅?
rival-black
rival-blackOP•3y ago
Yeah... I didn't want to bother you again 😄 @TkDodo 🔮 I keep getting the wrong results and i am out of ideas.. I am doing what you told me, which is using a setTimeout thou... but as you know it can bite me in the long run if the server is slow
rival-black
rival-black•3y ago
that's why I pointed you towards useEffect. It knows when rendering is "finished".
Is there a way to wait for queryClient to finish updating the component
the queryClient doesn't update the component. It updates the cache, the cache informs react to re-render the component, and then react does it (eventually). I mean, it's the same as this:
const [state, setState] = useState(['foo', 'bar'])

<div>{JSON.stringify(state)}</div>
<button onClick={() => {
setState(prev => [...prev, 'baz'])
window.print()
}})>click</button>
const [state, setState] = useState(['foo', 'bar'])

<div>{JSON.stringify(state)}</div>
<button onClick={() => {
setState(prev => [...prev, 'baz'])
window.print()
}})>click</button>
there is no way that window.print will reliably include baz if you invoke it from the same event handler, because that's just how react works. state updates that you perform are scheduled and not available within the same handler ...
rival-black
rival-blackOP•3y ago
got it not sure if i did it correctly... as i am still screaming I will copy my code and you judge it
const [imprimir, setImprimir] = useState(false)

const handleImprimir = async () => {
await queryClient.invalidateQueries(['ncf'])
setImprimir(true)
}

useEffect(() => {
if (imprimir) {
window.print()
setImprimir(false)
}
}, [imprimir])
const [imprimir, setImprimir] = useState(false)

const handleImprimir = async () => {
await queryClient.invalidateQueries(['ncf'])
setImprimir(true)
}

useEffect(() => {
if (imprimir) {
window.print()
setImprimir(false)
}
}, [imprimir])
BTW: Do i need to have await queryClient?
rival-black
rival-black•3y ago
awaiting the invalidation? yes.
metropolitan-bronze
metropolitan-bronze•3y ago
A nit simplification:
const [imprimir, setImprimir] = useState(false)

const handleImprimir = async () => {
await queryClient.invalidateQueries(['ncf'])
setImprimir(imprimir => !imprimir);
}

useEffect(() => {
window.print()
}, [imprimir])
const [imprimir, setImprimir] = useState(false)

const handleImprimir = async () => {
await queryClient.invalidateQueries(['ncf'])
setImprimir(imprimir => !imprimir);
}

useEffect(() => {
window.print()
}, [imprimir])

Did you find this page helpful?