Description
I would like to
- transfer components which render results depend on nondeterministic, direct function call(such as
Math.random()
orDate.now()
) and - fix the results before and after transfer, without storing them internally
- OutPortal for the components are conditional
And for these purposes, it seems like this package doesn't do what I expected.
Here's the MWE example: CodeSandbox Link
//Box.tsx
function Box({ txt }: BoxProps) {
return (
<div style={{ border: "1px solid red" }}>
<strong>{txt}</strong>
<br />
{Date.now()}
</div>
);
}
export const MemoBox = memo(Box);
//App.tsx
import { MemoBox } from "./Box";
function App() {
const [show, setShow] = useState(true);
const node1 = useMemo(createHtmlPortalNode, []);
const node2 = useMemo(createHtmlPortalNode, []);
const toggle = useCallback(() => { setShow((show) => !show); }, []);
return (
<>
<InPortal node={node1}> <MemoBox txt="111" /> </InPortal>
<InPortal node={node2}> <MemoBox txt="222" /> </InPortal>
<button onClick={toggle}>Click me!</button>
<div>
{show && <OutPortal node={node1} />}
{show && <OutPortal node={node2} />}
</div>
<div>
{!show && <OutPortal node={node1} />}
</div>
</>
);
}
Every time I toggle, Box "111" alters its position and Box "222" repeats hiding and showing. Now let's focus on the timestamp.
Box "111" prints with the fixed timestamp, because every render exposes either OutPortal node1. This is fine.
Box "222" however, the timestamp has changed on every show, and this behavior is not quite intuitive when the package description says:
Rendering to zero OutPortals is fine: the node will be rendered as normal, using just the props provided inside the InPortal definition, and will continue to happily exist but just not appear in the DOM anywhere.
rather, it looks like when OutPortal node2 is absent, the detached node2 has been garbage collected and previous timestamp is gone forever.
I'm aware that below solutions will fix Box "222" timestamp as well, so that my purposes are satisfied:
- modifying the
Box
implementation (namely usinguseEffect
anduseState
) to store the timestamp right after mounting - or even simpler, insert !show && OutPortal node2 as well but wrapped inside a
display:none
div.
yet I'm curious why did the timestamp change when the component is supposed to be memoized - given that without these portals React.memo()
will do its work and fix the whole results.