preact icon indicating copy to clipboard operation
preact copied to clipboard

Is it possible to make useDeferredValue to actually do something?

Open zsolt-dev opened this issue 1 year ago • 6 comments

It looks like useDeferredValue does nothing in Preact. This is a code from compat:

export function useDeferredValue(val) {
	return val;
}

Is it possible to implement useDeferredValue it in Preact? If yes, is there a plan for it? What would be a preferred workaround right now?

Thank you

zsolt-dev avatar Aug 07 '22 12:08 zsolt-dev

I mean, what is your use case for useDeferredValue we aren't rendering async so it can't really have an implementation afaict

JoviDeCroock avatar Aug 07 '22 12:08 JoviDeCroock

@JoviDeCroock

I was thinking maybe putting returning the last value and return current value after setTimeout: 0 ?

On server it would return new value straight away, like now...

Would that work? If you I could provide a PR.

zsolt-dev avatar Aug 07 '22 15:08 zsolt-dev

I personally don't really see the use of that 😅 our renders aren't interruptable and are prioritized according to depth so tearing can't occur, the value returned there is always the correct value for the current subtree. I am not entirely sure I get the use case here, if I understand correctly you are looking for a way to have the value of the previous render available while rendering and then when effects, ... run you want to leverage the current value.

JoviDeCroock avatar Aug 07 '22 15:08 JoviDeCroock

@JoviDeCroock

Yes, basically rerender with the old value (so everything else than the expensive stuff) and then change the value and rerender just the expensive stuff. The idea behind it is that user gets the feedback right away and the expensive stuff gets rerendered later.

@gaearon had some ideas about it too: https://github.com/preactjs/preact/pull/3510#discussion_r846627113

zsolt-dev avatar Aug 08 '22 10:08 zsolt-dev

@JoviDeCroock

Yes, basically rerender with the old value (so everything else than the expensive stuff) and then change the value and rerender just the expensive stuff. The idea behind it is that user gets the feedback right away and the expensive stuff gets rerendered later.

@gaearon had some ideas about it too: #3510 (comment)

The way to do that in preact would be with a useEffect.

ekwoka avatar Aug 23 '22 10:08 ekwoka

Thank you @ekwoka for your input.

Yes, you are right that useEffect is a way to achieve this.

But this issue is about preact-compat. When someone is switching from react code and expects useDeferredValue to do something. And since preact is not async, my proposed solution provides similar functionality without async.

@gaearon can you please explain what did you mean in your comment: https://github.com/preactjs/preact/pull/3510#discussion_r846627113 ?

I would be happy to create a PR for this.

zsolt-dev avatar Aug 30 '22 10:08 zsolt-dev

This is effectively what the hook does and how I implemented it in react-nylon:

function useDeferredValue<T>(value: T): T {
  const [deferredValue, setDeferredValue] = useState(value)

  useEffect(() => startTransition(() => setDeferredValue(value)), [value])

  return deferredValue
}

Since there's no async scheduler in Preact, you can omit startTransition (no-op), but the magic comes from useEffect which defers the callback via requestAnimationFrame.

CodyJasonBennett avatar Jun 27 '23 19:06 CodyJasonBennett