Closed crapthings closed 2 years ago
useEffect
and useLayoutEffect
work the same with one key difference. useEffect
yields after the first render, before useEffect
is run to allow the browser to update/paint. useLayoutEffect
does not yield, so that you can manipulate DOM elements.
Because of this difference, your are seeing that useLayoutEffect
does appear to update the view immediately when the route changes, but in reality, it's just delaying rendering. It "appears" to work like the old withTracker
but doesn't exactly - that used the deprecated componentWillMount
method, for which there is no hooks alternative.
As for useTracker
- it's true that it uses useEffect
because we don't want to block render/paint by default. But we also mitigate the lag by 1 problem, specifically because of issues uncovered with routing (react-router during development, but same idea). Routers tend to reuse mounted components, instead of of forcing a full lifecycle, so we use some tricks in useTracker
to avoid the problem. When deps change, it invalidates useMemo
and recreates the computation. You could also use useTracker
without deps
, which uses a different algorithm internally, one which always runs the computation inline with render. So there's never a lag! withTracker
uses the same internal algorithm (and always has!)
Alternatively, you could force a lifecylce change on route change by changing the key property of your route react element, which will force clear the useEffect
. That will force the component to be rebuilt in sync with render even when using deps
.
You could of course, roll your own useTracker
alternative - using useLayoutEffect
.
I wonder if folks would use a useLayoutTracker
🤔.
The problem is that might send the wrong signal. The truth is, renders should be cheap and disposable. Computations are also cheap and disposable. There's not really a problem that comes from double renders and the like, especially in concurrent mode, unless you measure a specific problem.
yes the tracker and react render is very cheap.
the only problem i think is
switch between two component share same meteor tracker aware reactive source
Comp1 first load
Comp1 tracker start to run
Comp2 about to switch
Comp1 last tracker rerun with Comp2's reactive source // this is will break things
Comp2 tracker start to run
Comp1 stop tracker then unmount
Yeah, that was a tricky problem we uncovered during the development of useTracker
. We ended up churning a LOT to get a solution to that which made sense. There is no perfect way to do it, but you can use useMemo
to make sure things change immediately when deps change (or roll your own deps compare), and then commit everything in useEffect
. But then you get double renders. You can try to retain the effect produced in useMemo
(like we used to do in useTracker
- but it's super hard, and hacky, and not really "the react way."
Is there a reason you aren't using useTracker
or withTracker
?
I'm closing this issue because we haven't heard anything from the original poster for a while.
what is different if we start tracker inside useEffect or useLayoutEffect?
i'm facing something like this
https://github.com/veliovgroup/flow-router/issues/88
so i've try to move tracker.autorun inside an useLayoutEffect, it looks the hook works like the old class component way.
https://reactjs.org/docs/hooks-reference.html#uselayouteffect
make tracker.autorun inside useEffect, will cause rerun before unmounting, so i want to prevent this