I've built a draggable slider component inside one of my pages, which changes the state of the info on a form as the tab is dragged further along the screen (horizontal only) but as the position changes and I set state in order to change the info on this form, it causes my page to re-render and as I am using useRef, it causes the page to re-render and useRef to be reset back to its original value.
How can I set the state so that the info on this form changes without re-rendering? so no matter if the user drags the tab left or right on the slider, it will render the correct info on the form and not reset the useRef once state is set.
This is an image of the slider to give you an idea, (the white tab is the draggable part)
And here is my code:
const FinancialLandingPage = () => {
const { t } = useTranslation();
const [selectedPlanDetails, setSelectedPlanDetails] = useState(SUBSCRIPTION_PLANS.newbie.name);
const DraggableComponent = () => {
const [pressed, setPressed] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
const [currentPlan, setCurrentPlan] = useState(1);
const ref = useRef();
// Monitor changes to position state and update DOM
useEffect(() => {
if (ref.current) {
ref.current.style.transform = `translate(${position.x}px`;
}
if (position.x > 0 && position.x < 147) {
setCurrentPlan(1);
setSelectedPlanDetails(SUBSCRIPTION_PLANS.newbie.name);
} else if (position.x > 147 && position.x < 294) {
setCurrentPlan(2);
setSelectedPlanDetails(SUBSCRIPTION_PLANS.enthusiast.name);
} else if (position.x > 294 && position.x < 441) {
setCurrentPlan(3);
setSelectedPlanDetails(SUBSCRIPTION_PLANS.trader.name);
} else if (position.x > 441 && position.x < 600) {
setCurrentPlan(4);
setSelectedPlanDetails(SUBSCRIPTION_PLANS.traderplus.name);
}
}, [position]);
// Update the current position if mouse is down
const onm ouseMove = useCallback(
(event) => {
if (pressed) {
if (position.x event.movementX < 0) {
setPosition({
x: 0,
y: position.y 0,
});
return;
}
if (position.x event.movementX >= 600) {
setPosition({
x: 610,
y: position.y 0,
});
return;
}
setPosition({
x: position.x event.movementX,
y: position.y 0,
});
}
},
[pressed, position]
);
return (
<div
ref={ref}
onm ouseMove={onMouseMove}
onm ouseDown={() => setPressed(true)}
onm ouseUp={() => setPressed(false)}
>
<div className="slider-bar-item">
<Heading level={"5"}>{t(base_t "page_five.slider").replace("[num]", currentPlan)}</Heading>
</div>
</div>
);
};
return (
<>
<div className={"slider"}>
<div className="slider-bar">
<DraggableComponent />
</div>
</div>
<div className={"form-container"}>
<div className={"header"}>
<Heading align={"center"} level={"3"}>
{t(base_t "page_five.form.title")}
</Heading>
<Heading align={"center"} level={"1"}>
{t(base_t
`page_five.form.${selectedPlanDetails}.price`)}
</Heading>
<Heading align={"center"} level={"6"}>
{t(base_t "page_five.form.price_description")}
</Heading>
</div>
<div className={"form"}>
<div className={"form-item"}>
<CryptoIcon name={"checkmark"} />
<Text size={16}>
{t(base_t
`page_five.form.${selectedPlanDetails}.item_one`)}
</Text>
</div>
<div className={"form-item"}>
<CryptoIcon name={"checkmark"} />
<Text size={16}>
{t(base_t
`page_five.form.${selectedPlanDetails}.item_two`)}
</Text>
</div>
<div className={"form-item"}>
<CryptoIcon name={"checkmark"} />
<Text size={16}>
{__(base_t
`page_five.form.${selectedPlanDetails}.item_three`)}
</Text>
</div>
<Button className={"button"}>
{t(base_t "page_five.form.button")}
<Icon name={"chevron_right"} />
</Button>
</div>
</div>
</>
);
export default FinancialLandingPage;
Thanks in advance!
CodePudding user response:
I think your issue is similar to the one described here: https://stackoverflow.com/a/75048172/8926512
In short, you are redefining DraggableComponent
on every rerender of the FinancialLandingPage
component, causing DraggableComponent
to be treated as a "new type" of component each time. As a result, during reconciliation, React will replace the old component type with the new component type and give it its initial state.
To fix this, you should move the definition of DraggableComponent
outside the FinancialLandingPage
component, and make any dependencies on FinancialLandingPage
passed in as props to DraggableComponent
.