accol
Coder
Thanks for reading. I can't figure out how to reparent card components to deck components when they overlap each other so the cards don't need to be destroyed and be recreated. Currently I'm just trying to figure out how to show them on the page properly using
Am I even approaching what I want to do correctly? Or is there a better way.
Please ignore the
Description on page about
react-reverse-portal
(used for reparenting) and it's not working. I also rarely use React so my apologies if I'm missing something obvious or just not understanding how React's supposed to work. The issue is that it seems like it's hitting all the breakpoints without problems, cardComponents
is being populated, CardBody
seems to be working, the console has no information.Am I even approaching what I want to do correctly? Or is there a better way.
JSX:
import React, { useState, useRef, useEffect } from 'react';
import ComponentContainer from '../../utils/component-container';
import CardBody from './card-body';
import Deck from './deck';
import Button from 'react-bootstrap/Button';
import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal';
const CardWorkspace = (props) => {
const [doesCardExist, setDoesCardExist] = useState(false);
const [cardComponents, setCardComponents] = useState([]);
const targetComponentRefs = useRef([]);
const cardPortalNode = createHtmlPortalNode({
attributes: {
id: "card",
style: "background-color: #aaf;" }
});
const [decks, setDecks] = useState([]);
const registerComponentRef = (ref, component) => {
if (ref.current && !targetComponentRefs.current.some(item => item.ref.current === ref.current)) {
targetComponentRefs.current.push({ ref, component });
}
};
const notifyOverlap = (componentRef, component) => {
if (!componentRef.current) return;
let rectCompA = componentRef.current.getBoundingClientRect();
let callback = (entries, observer) => {
entries.forEach(entry => {
// Should probably check via isIntersecting instead?
if (entry.target !== componentRef.current) {
let rectCompB = entry.target.getBoundingClientRect();
let doesOverlap = !(rectCompA.right < rectCompB.left ||
rectCompA.left > rectCompB.right ||
rectCompA.bottom < rectCompB.top ||
rectCompA.top > rectCompB.bottom);
// Temporary, check whether the overlapping card is already part of an existing deck
// If it is, add to that deck
// If not then create a new deck with it.
// This whole think really should be rewritten
// Not sure if IO are needed, just saw it recommended on StackOverflow
let overlappedComponent = targetComponentRefs.current.find(item => item.ref.current === entry.target);
if (overlappedComponent) {
let cards = [
component,
overlappedComponent.component
];
}
}
// I think the intersection check has issues, probably gotta fix the root and threshold
/*
if (entry.isIntersecting) {
console.log("Intersecting");
}*/
}
});
};
let io = new IntersectionObserver(callback, {
// root: el,
threshold: [0, 0.1, 0.95, 1]
});
targetComponentRefs.current.forEach(target => {
if (target.ref.current) {
io.observe(target.ref.current);
}
});
return () => {
targetComponentRefs.current.forEach(target => {
if (target.ref.current) {
io.unobserve(target.ref.current);
}
});
};
};
const addCardComponent = () => {
setCardComponents([...cardComponents,
<InPortal node = {cardPortalNode}>
<ComponentContainer
key = {cardComponents.length}
id={cardComponents.length}
registerComponentRef={registerComponentRef}
notifyOverlap={notifyOverlap}
>
<CardBody/>
</ComponentContainer>
</InPortal>
])
}
const updateCardExistence = useEffect(() => {
if (cardComponents.length > 0) {
setDoesCardExist(true);
}
else {
setDoesCardExist(false);
}
}, [cardComponents]);
return (
<div>
<Button variant="primary" onClick={addCardComponent}>
Add card
</Button>
<div>
{doesCardExist === true && (
<OutPortal node={cardPortalNode} bgColor="#aaf">
{cardComponents.map((cardComponent, index) => (
<React.Fragment key={index}>{cardComponent}</React.Fragment>
))}
</OutPortal>
)}
</div>
</div>
);
}
export default CardWorkspace;
Please ignore the
<div></div>
right below <div id="card" style="background-color: #aaf;height:1080px"></div>
, I had another one there. But I don't get why <div id="card" style="background-color: #aaf;height:1080px"></div>
has no children nested inside it, it should have ComponentContainer
and the CardBody
inside that.react-reverse-portal
Build an element once, move it anywhere. Latest version: 2.1.2, last published: 5 months ago. Start using react-reverse-portal in your project by running `npm i react-reverse-portal`. There are 29 other projects in the npm registry using react-reverse-portal.
www.npmjs.com
InPortal
:Render the content that you want to move around later.
InPortals render as normal, but send the output to detached DOM.
MyExpensiveComponent will be rendered immediately, but until
portalNode is used in an OutPortal, MyExpensiveComponent, it
will not appear anywhere on the page.
OutPortal
:Show the content of the portal node here: