I have a React Carousel that shows 3 elements at once. I would like to adjust this number of elements according to the size available. So for example
const RCarousel = ({items}) => {
const numItems = 3;
return (
<Carousel
numItemsPerView={numItems}
>
{
items.map(
(item) => <Item item={item} />
)
}
</Carousel>
)
}
I would like to change numItems to 2 if the RCarousel size is tablet size and 1 if is mobile size.
RCarousel may have a different width of the window width. Any suggestions how to make this? :)
You can use window.innerWidth and window.innerHight to get the size of the window.
Once you have the sizes, you can conditionally change it. I would stick the numItems in the useState and use useEffect to change it. Something along those lines
const [numItems, setNumItems] = useState(3);
const width = window.width;
useEffect(() => {
if (width > 800) {
setNumItems(3);
} else {
setNumItems(1);
}
}, [width])
Improving #szczocik's answer I was able to solve it using the following:
created a hook to get window size
useWindow.size.js
import {useState, useEffect} from 'react'
const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
if (typeof window === 'undefined') return; //specific for gatsby or applications using webpack
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener("resize", handleResize);
handleResize();
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
}
export default useWindowSize;
mycomponent.js
const windowSize = useWindowSize();
useEffect(() => {
const width = windowSize.width;
if (width >= 1200) {
if (numItems !== 3) {
setNumItems(3);
}
} else if (width > 900) {
if (numItems !== 2) {
setNumItems(2);
}
} else {
if (numItems !== 1) {
setNumItems(1);
}
}
}, windowSize)
Related
I want to increase the height of this image. How can we change the CSS for that? my code also have below image
You can create a custom component that will handle height and width, and use it.
You can do something like that.
import React, { useEffect, useState } from "react";
import { Image, ImageSourcePropType, ImageStyle, StyleProp } from "react-native";
interface ScaledImageProps {
source: ImageSourcePropType;
width?: number;
height?: number;
style?: StyleProp<ImageStyle> | undefined;
onGetHeight?: (height: number) => void
onGetWidth?: (width: number) => void
}
export const ScaledImage = (props: ScaledImageProps) => {
const [currentWidth, setCurrentWidth] = useState(0);
const [currentHeight, setCurrentHeight] = useState(0);
const setWidth = (width: number) => {
setCurrentWidth(width)
if (props.onGetWidth) props.onGetWidth(width)
}
const setHeight = (height: number) => {
setCurrentHeight(height)
if (props.onGetHeight) props.onGetHeight(height)
}
useEffect(() => {
const uri = Image.resolveAssetSource(props.source).uri
Image.getSize(uri, (width, height) => {
if (props.width && !props.height) {
setWidth(props.width);
setHeight(height * (props.width / width));
} else if (!props.width && props.height) {
setWidth(width * (props.height / height));
setHeight(props.height);
} else {
setWidth(width);
setHeight(height);
}
});
}, []);
return (
<Image
source={props.source}
style={[props.style ,{ height: currentHeight, width: currentWidth, }]}
/>
);
};
and if you want to use it, just call it like the following
<ScaledImage width={100} source={YourImage} />
I want to change the bg color of my navbar div once I scroll down. And if it's already at the top, I want to revert back to the original. I tried doing this following some code I got from a website.
I am using tailwind for CSS and React.
Is there a better way to do this? And is there some kind of fault with this code?
export default function Home(props) {
const [scrollPosition, setScrollPosition] = useState(0);
const [top, setTop] = useState(true)
const handleScroll = () => {
const position = window.scrollY;
setScrollPosition(position);
if (scrollPosition == 0) {
setTop(true)
} else if (scrollPosition > 10) {
setTop(false)
} else if (scrollPosition < 10) {
setTop(true)
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
})
return (
<div className={`${top ? 'bg-blue-500' : "bg-red-500"}`}>
</div>
);
}
I'm trying to hide some components when the screen hits some specific breakpoint.
My thought process was to store the screen width in a state then when it's below my breakpoint I set the display: none .
The question is how to access the screen width/viewport width in react? and is that the best approach for a responsive design?
Here's a simple example
const useWindowWide = (size) => {
const [width, setWidth] = useState(0)
useEffect(() => {
function handleResize() {
setWidth(window.innerWidth)
}
window.addEventListener("resize", handleResize)
handleResize()
return () => {
window.removeEventListener("resize", handleResize)
}
}, [setWidth])
return useWindowWidth > size
}
and to use it,
const Greeting = () => {
const wide = useWindowWide(600)
return (<h1>{wide ? "Hello World" : "Hello"}</h1>)
}
THere're quite a few hooks in the following reference might help you better.
seWindowSize, https://usehooks.com/useWindowSize/
useWindowSize, https://github.com/jaredLunde/react-hook/tree/master/packages/window-size
you can get width like this
const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
But can go alone with CSS to hide certain things in breakpoints and make responsive designs
Only correcting something that went wrong to me in the preview answer. This way worked for me:
const useWindowWide = (size) => {
const [width, setWidth] = useState(0)
useEffect(() => {
function handleResize() {
setWidth(window.innerWidth)
}
window.addEventListener("resize", handleResize)
handleResize()
return () => {
window.removeEventListener("resize", handleResize)
}
}, [setWidth])
return width
}
const wide = useWindowWide(400)
<h1>{wide >= 500 ? "Desktop" : "Mobile"}</h1>
I'm using photoswipe gallery.
When I do so, I get all the thumbnails in a single line... I would like them to fill the page like a grid.
Below is my react component code. I have noticed that if I go to each thumbnail in dev tools->inspect and change display to 'inline' I don't end up with a line break after/before each. It still looks garbage because lack of frames and other things, However, I don't know how or where to modify the look or styling of the thumbnails put that in my code.
import { PhotoSwipeGallery } from 'react-photoswipe-2';
const useStyles = makeStyles((theme) => ({
loadingPaper: {
margin: "auto",
width: '50%',
padding: '10px',
marginTop: "50px"
}
}));
function FrameViewer(props) {
const classes = useStyles();
let { cameraAccessor } = useParams();
const [frames, setFrames] = useState([]);
const [isGalleryOpen, setIsGalleryOpen] = useState(false);
const [imgGalleryH, setGalleryImgH] = useState(0);
const [imgGalleryW, setGalleryImgW] = useState(0);
const [cameraID, setCameraID] = useState("");
const { cameras } = props;
async function fetchCameraData(cameraAccessor) { // TODO: check if already loading before running. // code to get filenames and what not
}
useEffect(() => {
// code to lead camera data
}, [cameraAccessor]);
const getThumbnailContent = item => (
<img src={item.thumbnail} width={120} height={90} alt="" />
);
let cam = cameras[cameraID];
if (cam) { // Photoswipe requires a Height and Width ... so we need to load the first image and see how big before we can incept Photoswipe.
var img = new Image();
img.onload = function () {
setGalleryImgH(img.height);
setGalleryImgW(img.width);
}
img.src = "https://apps.usgs.gov/sstl/media/cameras/" + cameraFolderName(cam) + "/" + cameraFolderName(cam) + MOST_RECENT_FRAME_SUFFIX;
}
return (
<React.Fragment>
{cam && frames && frames.length && imgGalleryH > 0 && imgGalleryW > 0
? <PhotoSwipeGallery
items={frames.map((filename) => {
return {
src: 'https://example.com/media/cameras/' + cameraFolderName(cam) + '/' + filename,
thumbnail: 'https://example.com/media/cameras/' + cameraFolderName(cam) + '/' + filename,
w: imgGalleryW,
h: imgGalleryH,
title: filename.replace("_overlay.jpg", "").split("___")[1].replace("_", " ")
}
})}
options={{
closeOnScroll: false
}}
thumbnailContent={getThumbnailContent}
isOpen={isGalleryOpen}
onClose={() => setIsGalleryOpen(false)}
/>
: <Paper elevation={5} className={classes.loadingPaper}><Typography color="textSecondary" align='center'>loading...</Typography></Paper>
}
</React.Fragment >
);
}
Edit your CSS. Try overriding the display property at the container level (.pswp-thumbnails):
.pswp-thumbnails
{
display: flex;
}
... OR at the thumbnail level (.pswp-thumbnail):
.pswp-thumbnail {
display: inline-block;
}
How set react-select input width depending on biggest option width? Options position is absolute and therefore their size not affect parent div width.
It is example: https://codesandbox.io/s/9o4rkklz14
I need to select width was longest option width.
I've answered this in a few issue threads here and here for more background about complexities and caveats, but here is the gist of the approach.
You need to set the width of the menu to be auto so it will stretch to fit its contents.
onMount, style the menu (height: 0, visibility: hidden) and open the menu with the internal ref method
With the onMenuOpen prop, use a function that waits 1ms, get the width of the listMenuRef, and close/reset the menuIsOpen.
With the calculated width, you can now set the width of the ValueContainer.
The result can be seen here at this codesandbox
Code posted below...
import React, { useState, useRef, useEffect } from "react";
import Select from "react-select";
const App = (props) => {
const selectRef = useRef();
const [menuIsOpen, setMenuIsOpen] = useState();
const [menuWidth, setMenuWidth] = useState();
const [isCalculatingWidth, setIsCalculatingWidth] = useState(false);
useEffect(() => {
if (!menuWidth && !isCalculatingWidth) {
setTimeout(() => {
setIsCalculatingWidth(true);
// setIsOpen doesn't trigger onOpenMenu, so calling internal method
selectRef.current.select.openMenu("first");
setMenuIsOpen(true);
}, 1);
}
}, [menuWidth, isCalculatingWidth]);
const onMenuOpen = () => {
if (!menuWidth && isCalculatingWidth) {
setTimeout(() => {
const width = selectRef.current.select.menuListRef.getBoundingClientRect()
.width;
setMenuWidth(width);
setIsCalculatingWidth(false);
// setting isMenuOpen to undefined and closing menu
selectRef.current.select.onMenuClose();
setMenuIsOpen(undefined);
}, 1);
}
};
const styles = {
menu: (css) => ({
...css,
width: "auto",
...(isCalculatingWidth && { height: 0, visibility: "hidden" })
}),
control: (css) => ({ ...css, display: "inline-flex " }),
valueContainer: (css) => ({
...css,
...(menuWidth && { width: menuWidth })
})
};
const options = [
{ label: "Option 1", value: 1 },
{ label: "Option 2", value: 2 },
{ label: "Option 3 is a reallly realllly long boi", value: 3 }
];
return (
<div>
<div> Width of menu is {menuWidth}</div>
<Select
ref={selectRef}
onMenuOpen={onMenuOpen}
options={options}
styles={styles}
menuIsOpen={menuIsOpen}
/>
</div>
);
};
export default App;