useScroll, useScrolling, useHoverDirty does not work when used on initially unmounted element
What is the current behavior?
When referenced component initially unmounted, and mounted later (e.g on click) useScroll, useScrolling, useHoverDirty hooks have no effect.
Steps to reproduce it and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have extra dependencies other than react-use. Paste the link to your JSFiddle or CodeSandbox example below:
https://codesandbox.io/s/react-use-issue-ry7zk
What is the expected behavior?
Hooks should fire when component is mounted and do not when it is unmounted
A little about versions:
- OS: MaxOS 10.15
- Browser (vendor and version): Chrome 78
- React: 16.8.4
-
react-use: 12.9.1 - Did this worked in the previous package version? idk
I checked sources and saw there is [ref] object in deps of useEffect hook. It's pointless cause ref is mutable by design and it will not report any changes
It is a confusing scene for useRef. ref should never rerun effect or render when ref.current changed. So, you can solve it by moving these hooks inside a new sub-component. For more, if we need to measure ref.current, we should use useState and callback instead of useRef.
I solved my problem by writing my own hook with useState and callback as you say. It causes single additional rerender but thatβs ok for me. You can also achieve 0 additional rerenders if you provide createRef callback with hook and will attach/detach events inside it. But it will be a little less flexible.
Still a bug, I guess, cause having null in ref.current is valid behavior. And sometimes you cannot just change it (e.g integrating with 3d party staff)
Is this a bug? As suggested by @qianL93 , it can be solved by moving these hooks to a new child component. This issue should be closed, in my opinion.
It is a confusing scene for
useRef.refshould never rerun effect or render when ref.current changed. So, you can solve it by moving these hooks inside a new sub-component. For more, if we need to measure ref.current, we should useuseStateand callback instead ofuseRef.
@qianL93 could you explain this further or provide a minimal codesandbox?
having the same issue here. useScroll always return 0
Any solution?
Can I take this?
@aelsaman @lucasbara @sweetliquid @mikemajara Here's a simple example:
https://codesandbox.io/s/react-use-issue-forked-9gmzfg?file=/src/index.tsx
It combines an "initially unmounted element" with the useScrolling, useScroll and useHoverDirty hooks to create a child component.
import * as React from "react";
import { render } from "react-dom";
import { useScroll, useScrolling, useHoverDirty } from "react-use";
import "./styles.css";
const Workspace = () => {
const ref = React.useRef<HTMLDivElement>(null);
const { x, y } = useScroll(ref);
const isScrolling = useScrolling(ref);
const isHovering = useHoverDirty(ref);
return (
<div
ref={ref}
style={{ height: 400, width: 200, overflow: "auto", border: 1 }}
>
<div style={{ position: "fixed" }}>
positions: {JSON.stringify({ x, y })}
<br />
isScrolling: {JSON.stringify(isScrolling)}
<br />
hover: {JSON.stringify(isHovering)}
</div>
<div style={{ height: 800, width: 200, backgroundColor: "#0FC" }} />
</div>
);
};
function App() {
const [active, setActive] = React.useState(false);
return (
<div className="App">
<button onClick={() => (active ? setActive(false) : setActive(true))}>
TOGGLE
</button>
{active && <Workspace />}
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);