I'm using redux-sagas for store management, so when the request state is success, it should slide to the right using the ref. However, this behavior is not being reflected. What happens is that it doesn't slide to the right; I have to go back and forth with the arrows to display the data.
Home.jsx
const Component = ({
cohorts,
selectedAcademy,
cohortStates,
}: ComponentProps) => {
const dispatch = useDispatch();
const navigate = useNavigate();
const refToSlider: any = useRef(null);
const { isMobile } = useWindowSize();
const [isLoading, setIsLoading] = useState<boolean>(true);
const [thereAreItems, setThereAreItems] = useState<boolean>(true);
const [items, setItems] = useState<CohortDto[]>([]);
const fetchData = ({ page, filterBy }: FetchData) => {
console.log(page, "context pagedata");
let payload: { [key: string]: PaginationDto } = {
cohorts: {
limit: 4,
offset: 4 * page,
filterBy: {
...(filterBy ? filterBy : {}),
active: true,
},
},
};
/* const sortBy = page % 2 === 0 ? "viewCount" : "created_at";
const sortDirection = "desc"; */
payload = Object.entries(payload).reduce((acc, [key, value]) => {
acc[key] = { ...value /* sortBy, sortDirection */ };
return acc;
}, {});
dispatch(
getCohortsByAcademy({ _id: selectedAcademy._id, ...payload.cohorts })
);
};
const onOffsetChange = (newIndex) => {
fetchData({ page: newIndex });
};
useEffect(() => {
return () => {
dispatch(resetGetAllCohorts());
};
}, []);
useEffect(() => {
if (!isLoading && !!cohorts) {
setItems((state) => [...state, ...cohorts]);
setThereAreItems(!!cohorts && cohorts?.length === 4);
}
}, [cohorts, isLoading]);
useEffect(() => {
if (refToSlider.current && cohortStates.success) {
dispatch(resetGetAllCohortsStates());
refToSlider.current.nextSlide();
}
setIsLoading(cohortStates.loading);
}, [cohortStates, refToSlider, dispatch]);
return (
<>
<FlexContainer direction="column" gap="8px">
<BannerTitle size="16px">Próximos Cohorts</BannerTitle>
{!items ? (
<Loader color="LightBlue"></Loader>
) : (
<Slider
ref={refToSlider}
moreItems={thereAreItems}
limit={4}
onBeforeChange={onOffsetChange}
isLoading={isLoading}
>
{items.length > 0 ? (
items
/* .filter(
(cohort) =>
cohort.active &&
cohort.academy === selectedAcademy?._id &&
!cohort.hidden
) */
.map((cohort) => (
<Slide
onClick={() => {
dispatch(addClick({ _id: cohort._id }));
navigate(`/dashboard/cohort/${cohort._id}/home`);
}}
key={cohort._id}
>
<SlideImg
{...(isMobile && { style: { height: "200px" } })}
src={
cohort.picture ??
"https://repository-images.githubusercontent.com/410214337/070f2aba-d9d6-4699-b887-9a0f29015b1b"
}
></SlideImg>
<SlideTitle>{cohort.name}</SlideTitle>
<FlexContainer align="center" gap="6px">
<FlexContainer align="center" gap="3px">
<DotContent></DotContent>
<SlideSubTitle>
{`Inicio: `}
{!!cohort.startDate && (
<span>
{new Date(cohort.startDate).toLocaleDateString(
"en-GB"
)}
</span>
)}
</SlideSubTitle>
</FlexContainer>
<FlexContainer align="center" gap="3px">
<DotContent></DotContent>
<SlideSubTitle>
{`Finaliza: `}
{!!cohort.endDate && (
<span>
{new Date(cohort.endDate).toLocaleDateString(
"en-GB"
)}
</span>
)}
</SlideSubTitle>
</FlexContainer>
</FlexContainer>
</Slide>
))
) : (
<FlexContainer style={{ width: "100%" }} justify="center">
<h2>No hay Cohorts</h2>
</FlexContainer>
)}
</Slider>
)}
</FlexContainer>
</>
);
};
const states = ({ cohortStore, academyStore }) => {
const { data: cohorts, states: cohortStates } = cohortStore.allCohorts;
const { data: selectedAcademy } = academyStore.selected;
return {
cohorts,
selectedAcademy,
cohortStates,
};
};
export default connect(states)(Component);
In the slider to display the data, I use the 'children' property. If the index plus the limit is greater than the number of items in the 'children' property, it executes the function to fetch more data. Otherwise, it moves forward by increasing the index.
Slider.jsx
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import "./style.css";
import { SlideBlur } from "./style";
import React, {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
import Loader from "../../../../components/Loader";
interface ComponentProps {
children: any;
disabled?: boolean;
noElements?: boolean;
onBeforeChange?: any;
limit: number;
moreItems?: boolean;
isLoading?: boolean;
}
function SampleNextArrow(props) {
const { className, style, onClick, loading } = props;
return (
<button disabled={loading} className={"slick-next-new"} onClick={onClick} />
);
}
function SamplePrevArrow(props) {
const { className, style, onClick, loading } = props;
return (
<button disabled={loading} className={"slick-prev-new"} onClick={onClick} />
);
}
const Component = forwardRef(
(
{
children,
disabled,
noElements,
onBeforeChange,
limit,
moreItems,
isLoading,
}: ComponentProps,
ref
) => {
const sliderRef: any = useRef(null);
const totalSlides = React.Children.count(children);
const [currentIndex, setCurrentIndex] = useState(0);
useImperativeHandle(
ref,
() => ({
nextSlide: () => {
if (sliderRef.current && !isLoading) {
sliderRef.current.slickNext();
}
},
prevSlide: () => {
if (sliderRef.current && !isLoading) {
sliderRef.current.showPreview();
}
},
}),
[sliderRef, isLoading]
);
const handleNextArrowClick = () => {
if (!isLoading && !!moreItems) {
setCurrentIndex((prevIndex) => prevIndex + 1);
}
};
const handlePrevArrowClick = () => {
if (!isLoading && currentIndex > 0) {
setCurrentIndex((prevIndex) => prevIndex - 1);
sliderRef.current.slickPrev();
}
};
const settings = {
dots: false,
infinite: false,
speed: 500,
slidesToShow: limit,
slidesToScroll: limit,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 4,
slidesToScroll: 4,
},
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
initialSlide: 2,
},
},
{
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
},
},
],
arrows: true,
className: `${!!disabled ? "fade" : ""}`,
};
useEffect(() => {
if (currentIndex + limit >= totalSlides) {
!!onBeforeChange && onBeforeChange(currentIndex);
}
}, [currentIndex, limit]);
return (
<>
{!!disabled ? (
<div
style={{
position: "relative",
width: "100%",
...(!!noElements && { minHeight: "200px" }),
}}
>
<SlideBlur></SlideBlur>
<Slider {...settings}>{children}</Slider>
</div>
) : (
<div style={{ position: "relative" }}>
<Slider ref={sliderRef} {...settings}>
{children.length === 0 ? (
<Loader color="LightBlue"></Loader>
) : (
children
)}
</Slider>
{!!moreItems && (
<SampleNextArrow
loading={isLoading}
onClick={handleNextArrowClick}
/>
)}
{currentIndex > 0 && (
<SamplePrevArrow
loading={isLoading}
onClick={handlePrevArrowClick}
/>
)}
</div>
)}
</>
);
}
);
export default Component;