Closed theKashey closed 5 years ago
Let me elaborate more on this:
setState
, and useRef
.useMemo
, useCallback
should be considered as derived data generators and could be rerun at any time.useEffect
in any form is a side effect with not deterministic execution moment (no execution on a server side for example), thus should be good to have.constructors
and destructors
always should be paired.useEffect
might have a destructor
.PS: useState
theoretically could be updated on HMR, but there is no way to update(not reset) useRef
.
function useSynchronousEffect(func, values) {
const [key] = useRef({});
let output;
// store "generation" key. Just returns a new object every time
const currentKey = useMemo(() => {}, values); // eslint-disable-line react-hooks/exhaustive-deps
// "the first render", or "memo dropped the value"
if(key.current !== currentKey){
ref.current = currentKey;
output = func();
}
React.useEffect(
() => output, // there is no need of a complex construction here.
[currentKey], // eslint-disable-line react-hooks/exhaustive-deps
// ^ use the same variable here.
);
}
Use effect
on SSR, and switch to useEffect
on CSR.
const useSynchronousEffect = isServer ? (effect, props) => effect() : useEffect
The problem - there is no way to detect is this "Server" or "Not". It's not bound to the environment, but to the react command used to kick off the render. Probably it should be
function useSynchronousEffect(func, values) {
const isServer = React.useContext(IsServer); // But still - who will set this value?
isServer ? effect : useEffect(effect, values);
}
I'm looking into it.
@oliviertassinari Hey Oliver, have you had any chance to look into this yet? This has been bugging me in the current project I am working on.
I've doublechecked this behavior with upcoming React Fresh, and it would be the same. So we have to find a solution, compatible with these constraints, but I am not sure that MUI shall do it by their own, as long as any project might need that Synchronous Effect, in the same way MUI needs it.
@theKashey Thanks for checking! I haven't looked into it yet, to be honest, but I hope we can release a v4.1.1 tomorrow with a fix and the TypeScript icon regression fix. This hook logic also has an issue with the Concurrent Mode, the problem is related.
It's fixed in https://github.com/mui-org/material-ui/pull/16195 and will be soon released in Material-UI v4.1.1.
Source issue - https://github.com/gaearon/react-hot-loader/issues/1262
One of the biggest issues for React-Hot-Loader in the last past months were hooks, which were not working properly, especially from the hot-loading point of view.
Version 4.9.0 introduced the fix for it via adding one more argument to every hook with dependencies, like
useEffect
.The Problem
useSynchronousEffect
is split into two parts - apply the effect, and remove it.useEffect
, and got called during hot updateThis issue should be solved regardless of the nature of hooks hot reloading - a special logic like this should be a bit more reliable.
values.length
expected to never be changed during the component life cycle (rules of hooks)useSynchronousEffect
touseEffect
on clientside (the best option)you may use
useMemo
to check stored values, but it still not quite stable, as longuseMemo
light drop the cache, and it makes this hooks more complex.