Reputation: 21
How/can we make number of visibleSlides responsive in CSS? / not have to use JS to alter visibleSlides
based on breakpoints.
For example;
Each slide has min-width: 100px; min-height: 100px;
ie. image we want to see detail so shouldn't be smaller than 100px.
We set visibleSlides
to 8 (for desktop). On mobile we want to show only 2 slides. Because we don't want the individual slides to be less than 100px height and width, nor have the slides overlapping.
I know we could use react to check screen width and set visibleSlides
, however it's not easy for all apps to have access to this, especially server side rendered like next.js.
See this sandbox https://codesandbox.io/s/pure-react-carousel-responsive-visible-slides-k8cui
(Forked from https://codesandbox.io/s/withered-wood-4bx36?fontsize=14&hidenavigation=1&theme=dark)
Upvotes: 2
Views: 3879
Reputation: 89
How about setting a state and using useEffect to update the state on resize of window, then passing down the window size as a prop to the carousel component and choosing the number of visibleslides using the prop?
Upvotes: 0
Reputation: 214
I had that problem for my app and actually couldn't find a way to do this with CSS
. However, I've implemented this using ResizeObserver
and react-hooks
.
P.S. I'm using next js
, and it's not a big issue to implement it on the server-side.
Here's my solution, hope it could help.
Step 1. Create an observer hook to listen for resize events from the app.
import { useEffect, useState, RefObject } from 'react';
import ResizeObserver from 'resize-observer-polyfill';
interface DOMRectReadOnly {
readonly bottom: number;
readonly height: number;
readonly left: number;
readonly right: number;
readonly top: number;
readonly width: number;
readonly x: number;
readonly y: number;
}
interface useResizeObserverProperties {
ref?: RefObject<Element> | null;
element?: Element | null | undefined;
callback?: (entry: ResizeObserverEntry) => void;
}
const IS_BROWSER = typeof window !== 'undefined';
/**
* Watch for the resizing of a React component or Element.
*
* @param hookProperties - Configuration optinos for the hook.
*
* @returns The `DOMRect` for the observed element.
*/
export const useResizeObserver = ({
ref,
element,
callback,
}: useResizeObserverProperties) => {
const [sizes, setSizes] = useState<DOMRectReadOnly>({
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0,
x: 0,
y: 0,
});
const handleResize = (entries: ResizeObserverEntry[]) => {
const [entry] = entries;
if (callback) callback(entry);
setSizes(entry.contentRect);
};
const [resizeObs] = useState(() =>
IS_BROWSER ? new ResizeObserver(handleResize) : undefined,
);
useEffect(() => {
if (!resizeObs) return;
let domNode;
if (ref) {
domNode = ref.current;
} else if (element) {
domNode = element;
}
if (domNode) {
resizeObs.observe(domNode);
}
return () => resizeObs.disconnect();
}, [ref, resizeObs, element]);
return sizes;
};
Step 2. In your component.tsx
import React, { useState, useRef } from 'react';
import { CarouselProvider, Slider, Slide } from 'pure-react-carousel';
import { useResizeObserver } from 'from previously created file';
const YourComponent = () => {
const [visibleSlides, setVisibleSlides] = useState(1);
const ref = useRef<HTMLDivElement>(null);
// Current width of element
const { width } = useResizeObserver({ ref });
switch (true) {
case width > 768 && width < 1280:
setVisibleSlides(2);
break;
/**
* Switch your cases here
*/
}
return (
<div ref={ref}>
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
visibleSlides={visibleSlides}
>
<Slider>
<Slide index={0}>Slide 1</Slide>
<Slide index={1}>Slide 2</Slide>
<Slide index={2}>Slide 3</Slide>
</Slider>
</CarouselProvider>
</div>
);
};
export default YourComponent;
Btw I'll recommend you throttle
setVisibleSlides
calls to avoid too much re-renders while resizing the window from dev-tools.
Upvotes: 2
Reputation: 171
not an answer, but i'm trying to do the same.
How about using React hooks useState
for the visibleSlides
integer, and creating a window listener that listens for breakpoints and changes the state as needed....
Upvotes: 0