ReactJs Functional Component Get When Scroll Reached End - javascript

I have a functional component in ReactJs and want to add pagination to my page so that when the user reaches end of the screen, I'd get the rest of the data from Api.
my code looks like this:
<div
className="MyOrdersHistory-list-container">
{ordersList.map((order, index) => (
<div key={index} className="MyOrdersHistory-listItem-container">
........
</div>
))}
</div>
How can I figure out when use scrolls to the end of the page to fire the Api request. (If possible please give a functional component example not a class one)
Thanks

import React, { useRef, useEffect } from 'react';
const <YourComponent> = () => {
const list = useRef();
const onScroll = () => {
if (list.current) {
const { scrollTop, scrollHeight, clientHeight } = list.current;
if (scrollTop + clientHeight === scrollHeight) {
// DO SOMETHING WHAT YOU WANT
}
}
};
...
<div
onScroll={() => onScroll()} ref={list}
className="MyOrdersHistory-list-container">
{ordersList.map((order, index) => (
<div key={index} className="MyOrdersHistory-listItem-container">
........
</div>
))}
</div>

Related

Scroll to top when changing pages

I have a pagination component (React). I need the scroll to be moved to the top when changing pages. Can someone help me?
const MAX_BTN = 9;
const MAX_BTN_LEFT = (MAX_BTN - 1) / 2;
const Pagination = ({items, limit = 20, page, setPage}) => {
const pages = items !== null && Math.ceil(items.total_results / limit);
const startBtn = Math.max(page - MAX_BTN_LEFT, 1);
return (
<ul className="pagination">
{Array(Math.min(MAX_BTN, pages)).fill()
.map((_, i) => i + startBtn)
.map(value => (
<li key={value}>
<button onClick={() => setPage(value)}>{value}</button>
</li>
))
}
</ul>
)
}
export default Pagination;
You can return to the top with a function:
const handlePageChange = value => {
window.scrollTo(0, 0);
setPage(value);
}
And calling it in your button:
...
<li key={value}>
<button onClick={() => handlePageChange(value)}>{value}</button>
</li>
call the browser window object with below method scrollTo when you click on the Link
window.scrollTo(0, 0);
An elegant way to handle this is by creating a single ref for the top-most part of your app. Then pass the ref into a hook which handles scrolling to the top of the page when the pathname changes.
Here's a simple hook I use (type definitions can be cleaned up):
useScrollToTop.ts
import { useEffect } from 'react';
import { useLocation } from 'react-router';
const useScrollToTop = (ref: any) => {
const location = useLocation();
// ensure pages scroll to top
useEffect(() => {
if (ref?.current) {
ref.current.scrollIntoView();
}
}, [ref?.current, location.pathname]);
return null;
};
export default useScrollToTop;
Now at the top of your app's very first element add the reference.
App.js: (or whatever component)
import useScrollToTop from './useScrollToTop';
Then create a new empty ref:
const ref = useRef<HTMLDivElement | null>(null);
Pass the ref into the hook:
useScrollToTop(ref)
Define the ref on the top-most part of your app (example inner components):
return (
<div ref={ref}>
<Header />
<Navigation />
<Content />
<Footer ?>
</div>
);
Now anytime the path changes, your end-user will scroll to the top of the page.

Performance cost when using custom hooks to detect element height React

The common problem of having a position: fixed header and applying consistent padding to the content below it so that nothing is covered. If the content inside of the header is dynamically subject to changing and the styling needs to stay consistent regardless of what is added or removed.
I implemented this hook:
export const useElemHeight = () => {
const elementRef = useRef(null);
const [heightOfEl, setHeightOfEl] = useState(null);
function handleCheckElHeightOnScreenResize() {
setHeightOfEl(elementRef.current.clientHeight);
}
useEffect(() => {
if (elementRef.current) {
setHeightOfEl(elementRef.current.clientHeight);
window.addEventListener("resize", handleCheckElHeightOnScreenResize);
return () => {
window.removeEventListener("resize", handleCheckElHeightOnScreenResize);
};
}
}, [elementRef]);
return [elementRef, heightOfEl];
};
Application
export default function App() {
const [elementRef, heightOfEl] = useElemHeight();
return (
<div className="App">
<Header ref={elementRef} />
<Content height={heightOfEl} />
</div>
);
}
const Content = ({ height }) => {
const ADDITIONAL_UNITS = 20;
return (
<div
className="content"
style={{ paddingTop: `${height + ADDITIONAL_UNITS}px` }}
>
CONTENT
</div>
);
};
export default Content;
regardless of what content is added or removed from the header the padding will always stay consistent via all screen sizes, but are there any real performance costs to implementing something like this? Working demo here.
Sandbox

How to show a Modal once onShowMoreClick is clicked?

<OneProfileKeyCard
title="Qualification"
showMoreText="See all qualifications"
onShowMoreClick={() => console.log('show more')}
>
Creating, communicating, and implementing the organization&apos;s vision, mission, and overall direction Leading the development and implementation of the overall organization&apos;s strategy.
</OneProfileKeyCard>
import React from 'react'
import './OneProfileKeyCard.scss'
type Props = {
title: string
showMoreText: string
onShowMoreClick: () => void
}
export const OneProfileKeyCard: React.FC<Props> = ({
title,
showMoreText,
onShowMoreClick,
children
}) => (
<div className="one-profile-key-card">
<h3>{ title }</h3>
<div>
{ children }
</div>
<button type="button" onClick={onShowMoreClick}>
{ showMoreText }
</button>
</div>
)
could anyone help me to set up a modal? Im trying to set up a modal once onShowMoreClick is clicked that would turn the children(creating, communicating, and implementing the organization...) into a modal. So far it looks like this:
You will need to have a state-managed in the parent component of where the OneProfileKeyCard child component is called from.
Something like this
const Parent = () => {
const [modalOpen, setModalOpen] = React.useState(false)
return (
<div>
<h1>Demo</h1>
<OneProfileKeyCard
title="Qualification"
showMoreText="See all qualifications"
onShowMoreClick={() => setModalOpen(!modalOpen)}>
text ... text
</OneProfileKeyCard>
</div>
)
}
I'm not sure what else is within your components, but you'll then need a way to close the model, right now I have set the showMoreClick prop to open/close, but if that should open then set it to true and do a similar pass-through for a closing false function.

How to make the carousel scroll only when the cursor is on it, istead of anywhere on the windows?

I am using react-elastic-carousel in my app to scroll vertically between four components and each of them has some infos to show when scrolling on them. What I want to do is that the scrolling functionality should be happend only when the cursor is on the carousel and not everywhere on the page like is currently happening now. how I can make it possible any advices? Thanks a lot.
Here is what I did so far:
codesandbox.io/s/compassionate-leftpad-zzueys?file=/src/App.js
News.js:
import React, {useEffect, useRef } from "react";
import Carousel from "react-elastic-carousel";
import "./ news.css";
import {
Center,
Areas,
Place,
Others,
} from "./Contents";
const News = () => {
useEffect(() => {
document.title = "News";
});
const prevItemObject = "prev";
const nextItemObject = "next";
const slider = useRef(null);
function scroll(e) {
if (slider === null) return 0;
e.wheelDelta > 0
? slider.current.onNextStart(prevItemObject, nextItemObject)
: slider.current.onPrevStart();
}
useEffect(() => {
window.addEventListener("wheel", scroll, true);
return () => {
window.removeEventListener("wheel", scroll, false);
};
}, []);
return (
<div className="container">
<Carousel
onScroll={scroll}
verticalMode
itemsToShow={1}
enableSwipe={true}
ref={slider}
>
<Relevant />
<SearchByAreas />
<FindAPlaceToLive />
<FindTheRightRoomie />
</Carousel>
</div>
);
};
export default News;
App.js:
import React from "react";
import News from "./News";
const App = () => {
return (
<div>
<News />
</div>
);
};
export default App;
your wheel event listener is on window for now, it will listen all the wheel events on the window. Maybe you could add the listener on the slider ref like this :
slider.current.addEventListener("wheel", scroll, true);
Could you provide a codepen sample please ? It would be easier to test it ;)

How can I synchronize the "scrollLeft" property of 2 divs while scrolling horizontally within a react component?

I would like to "synchronize" the x-position of 2 "divs" within a react component. Eventually, I would like to have a table header that stays always visible and a table that can scroll vertically. The horizontal offset of that table header and that table are supposed to remain "in sync".
The "onScroll" event fires. However, changing the "state" of the property "offsetX" in my function reactToScrolling has no effect on my "divs" (as far as I can see). What can I do to make this work?
const { useState } = require('react');
const MainComponent = () => {
const [ offsetX, setOffsetX ] = useState(0);
function reactToScrolling(e) {
console.log(e.target.scrollLeft);
setOffsetX(e.target.scrollLeft);
}
return (
<>
<div style={{ height:'200pt', width:'800pt', overflow:'scroll'}} onScroll={reactToScrolling}>
<div style={{ height:'600pt', width:'1600pt', backgroundColor:'red' }} scrollLeft={offsetX}>
...
</div>
</div>
<div style={{ height:'200pt', width:'800pt', overflow:'scroll'}} onScroll={reactToScrolling}>
<div style={{ height:'600pt', width:'1600pt', backgroundColor:'blue' }} scrollLeft={offsetX}>
...
</div>
</div>
</>
)
};
export default MainComponent;
Eventually, I found the solution myself. It works perfectly if useRef is used instead of useState. When the scroll event fires, the scrollLeft property of div1 is set to the value of the scrollLeft property of div2 using the references created with useRef.
const { useRef } = require('react');
const MainComponent = () => {
const div1 = useRef(null);
const div2 = useRef(null);
const onScroll = () => {
div1.current.scrollLeft = div2.current.scrollLeft;
}
return (
<>
<div ref={div1} style={{ height:'200pt', width:'800pt', overflow:'scroll'}} onScroll={onScroll}>
<div style={{ height:'600pt', width:'1600pt', backgroundColor:'lightgray' }}>
...
</div>
</div>
<div ref={div2} style={{ height:'200pt', width:'800pt', overflow:'scroll'}} onScroll={onScroll}>
<div style={{ height:'600pt', width:'1600pt', backgroundColor:'lightgray' }}>
...
</div>
</div>
</>
)
};
export default MainComponent;
Thanks, this helped me a lot.
For a final touch, I just added another function for the top div so that it can handle the scrolling itself too.
const onScrollTop = () => {
div2.current.scrollLeft = div1.current.scrollLeft;
}

Categories

Resources