I want to increase height of this react native curve image - css

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} />

Related

window width in react

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>

react photoswipe gallery of thumbnails will not display as grid

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 to make a responsive number os slides in a react carousel

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)

How to fix slider issue?

I have my Tabs working just fine. If you click on the plus symbol (+) you will be able to add Tabs and maybe after adding 3 or 4 tabs you'll see tabBar scroller buttons on both ends. This has been done using ExtJS and it works great!
Working Code:
Example Code
Basically, after certain width I would like to show those the scroller that will allow the user to navigate from right-left or left-right. Does anyone know how to accomplish this? Thanks a lot in advance!
Here's my code:
PLUNKER
<p-tabView>
<p-tabPanel header="one">
<button (click)="showSecondTab()">Show Second Tab</button>
</p-tabPanel>
<p-tabPanel header="two">
</p-tabPanel>
<p-tabPanel header="three">
</p-tabPanel>
<p-tabPanel header="fourt">
</p-tabPanel>
<p-tabPanel header="five">
</p-tabPanel>
.......
.......
.......
</p-tabView>
For now there is no built-in feature in primeng package. So I would consider writing some directive which will implement all desired behavior and take all hard work on itself.
This directive is going to have all stuff for handling such events such as window:scroll, click|long click on arrows, mousewhell on tabs. For such things i'm goung to use rxjs streams.
Also it's going to do some DOM manipulation like wrapping tabs in container and creating arrows.
It also will handle changes for p-tabPanel components through ContentChildren.changes
Finally, the result should look like:
tab-scroller.directive.ts
import { Directive, ElementRef, NgZone, Input, ContentChildren, QueryList } from '#angular/core';
import { TabPanel } from 'primeng/primeng';
import { interval } from 'rxjs/observable/interval';
import { of } from 'rxjs/observable/of';
import { fromEvent } from 'rxjs/observable/fromEvent';
import { Subject } from 'rxjs/Subject';
import { takeUntil } from 'rxjs/operators/takeUntil';
import { mergeMap } from 'rxjs/operators/mergeMap';
import { take } from 'rxjs/operators/take';
import { delay } from 'rxjs/operators/delay';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/of';
#Directive({
selector: '[tabScroller]',
})
export class TabScrollerDirective {
#Input() arrowWidth = 30;
#Input() shiftWidth = 25;
#ContentChildren(TabPanel) tabPanels: QueryList<TabPanel>;
private _container: HTMLElement;
private _nav: HTMLElement;
private _shift = 0;
private _scrollable: boolean;
private _leftArrow: HTMLElement;
private _rightArrow: HTMLElement;
private readonly _destroyed$ = new Subject<void>();
constructor(
private elRef: ElementRef,
private zone: NgZone) { }
get rightBorder() {
return -(this._nav.scrollWidth - this._nav.offsetWidth);
}
ngAfterContentInit() {
this.tabPanels.changes
.pipe(takeUntil(this._destroyed$))
.subscribe(() => {
this.zone.onStable.asObservable()
.pipe(take(1))
.subscribe(() => this._refreshScroller());
})
}
ngAfterViewInit() {
this.zone.runOutsideAngular(() => this.init());
}
init() {
this._nav = this.elRef.nativeElement.querySelector('[role=tablist]');
this._container = wrap(this._nav, 'nav-wrapper');
this._initEvents();
this._leftArrow = this._createArrow('left');
this._rightArrow = this._createArrow('right');
this._refreshScroller();
}
scroll(shift: number) {
this._shift += shift;
const rightBorder = this.rightBorder;
if (this._shift < rightBorder) {
this._shift = rightBorder;
}
if (this._shift >= 0) {
this._shift = 0;
}
this._leftArrow.classList.toggle('nav-arrow--disabled', this._shift >= 0);
this._rightArrow.classList.toggle('nav-arrow--disabled', this._shift <= rightBorder);
this._nav.style.transform = `translateX(${this._shift}px)`;
}
ngOnDestroy() {
this._destroyed$.next();
this._destroyed$.complete();
}
private _initEvents() {
fromEvent(this._container, 'mousewheel')
.pipe(takeUntil(this._destroyed$))
.subscribe((e: any) => this._onMouseWheel(e));
// Firefox
fromEvent(this._container, 'DOMMouseScroll')
.pipe(takeUntil(this._destroyed$))
.subscribe((e: any) => this._onMouseWheel(e));
fromEvent(window, 'resize')
.pipe(takeUntil(this._destroyed$))
.subscribe(() => {
this._refreshScroller();
});
}
private _onMouseWheel(e: any) {
const delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
this.scroll(delta * 25);
}
private _createArrow(direction: string) {
const arrow = el(`nav-arrow nav-arrow--${direction}`);
this._container.insertBefore(arrow, this._nav);
arrow.style.width = this.arrowWidth + 'px';
fromEvent(arrow, 'click')
.pipe(takeUntil(this._destroyed$))
.subscribe(() => {
this.scroll(direction === 'left' ? this.shiftWidth : -this.shiftWidth);
});
const upStream$ = fromEvent(arrow, 'mouseup');
// handle long press
fromEvent(arrow, 'mousedown')
.pipe(
takeUntil(this._destroyed$),
mergeMap((event) => interval(100).pipe(delay(100), takeUntil(upStream$)))
)
.subscribe(() => {
this.scroll(direction === 'left' ? this.shiftWidth : -this.shiftWidth);
});
return arrow;
}
private _refreshScroller() {
const compareWith = (this._scrollable ? -this.arrowWidth * 2 : 0);
this._container.classList.toggle('nav-wrapper--scrollable', this.rightBorder < compareWith);
this._scrollable = this.rightBorder < compareWith;
this.scroll(0);
}
}
function wrap(elem, wrapperClass: string) {
const wrapper = el('nav-wrapper');
elem.parentNode.insertBefore(wrapper, elem);
wrapper.appendChild(elem);
return wrapper;
}
function el(className: string): HTMLElement {
const div = document.createElement('div');
div.className = className;
return div;
}
The last thing you need to do is to apply this directive on p-tabView element:
<p-tabView tabScroller>
...
</p-tabView>
Plunker Example
Ng-run Example

React Native: Different styles applied on orientation change

I'm developing a React Native application to be deployed as a native application on iOS and Android (and Windows, if possible).
The problem is that we want the layout to be different depending on screen dimensions and its orientation.
I've made some functions that return the styles object and are called on every component render's function, so I am able to apply different styles at application startup, but if the orientation (or screen's size) changes once the app has been initialized, they aren't recalculated nor reapplied.
I've added listeners to the top rendered so it updates its state on orientation change (and it forces a render for the rest of the application), but the subcomponents are not rerendering (because, in fact, they have not been changed).
So, my question is: how can I make to have styles that may be completely different based on screen size and orientation, just as with CSS Media Queries (which are rendered on the fly)?
I've already tried react-native-responsive module without luck.
Thank you!
If using Hooks. You can refer to this solution: https://stackoverflow.com/a/61838183/5648340
The orientation of apps from portrait to landscape and vice versa is a task that sounds easy but may be tricky in react native when the view has to be changed when orientation changes. In other words, having different views defined for the two orientations can be achieved by considering these two steps.
Import Dimensions from React Native
import { Dimensions } from 'react-native';
To identify the current orientation and render the view accordingly
/**
* Returns true if the screen is in portrait mode
*/
const isPortrait = () => {
const dim = Dimensions.get('screen');
return dim.height >= dim.width;
};
/**
* Returns true of the screen is in landscape mode
*/
const isLandscape = () => {
const dim = Dimensions.get('screen');
return dim.width >= dim.height;
};
To know when orientation changes to change view accordingly
// Event Listener for orientation changes
Dimensions.addEventListener('change', () => {
this.setState({
orientation: Platform.isPortrait() ? 'portrait' : 'landscape'
});
});
Assembling all pieces
import React from 'react';
import {
StyleSheet,
Text,
Dimensions,
View
} from 'react-native';
export default class App extends React.Component {
constructor() {
super();
/**
* Returns true if the screen is in portrait mode
*/
const isPortrait = () => {
const dim = Dimensions.get('screen');
return dim.height >= dim.width;
};
this.state = {
orientation: isPortrait() ? 'portrait' : 'landscape'
};
// Event Listener for orientation changes
Dimensions.addEventListener('change', () => {
this.setState({
orientation: isPortrait() ? 'portrait' : 'landscape'
});
});
}
render() {
if (this.state.orientation === 'portrait') {
return (
//Render View to be displayed in portrait mode
);
}
else {
return (
//Render View to be displayed in landscape mode
);
}
}
}
As the event defined for looking out the orientation change uses this command ‘this.setState()’, this method automatically again calls for ‘render()’ so we don’t have to worry about rendering it again, it’s all taken care of.
Here's #Mridul Tripathi's answer as a reusable hook:
// useOrientation.tsx
import {useEffect, useState} from 'react';
import {Dimensions} from 'react-native';
/**
* Returns true if the screen is in portrait mode
*/
const isPortrait = () => {
const dim = Dimensions.get('screen');
return dim.height >= dim.width;
};
/**
* A React Hook which updates when the orientation changes
* #returns whether the user is in 'PORTRAIT' or 'LANDSCAPE'
*/
export function useOrientation(): 'PORTRAIT' | 'LANDSCAPE' {
// State to hold the connection status
const [orientation, setOrientation] = useState<'PORTRAIT' | 'LANDSCAPE'>(
isPortrait() ? 'PORTRAIT' : 'LANDSCAPE',
);
useEffect(() => {
const callback = () => setOrientation(isPortrait() ? 'PORTRAIT' : 'LANDSCAPE');
Dimensions.addEventListener('change', callback);
return () => {
Dimensions.removeEventListener('change', callback);
};
}, []);
return orientation;
}
You can then consume it using:
import {useOrientation} from './useOrientation';
export const MyScreen = () => {
const orientation = useOrientation();
return (
<View style={{color: orientation === 'PORTRAIT' ? 'red' : 'blue'}} />
);
}
You can use the onLayout prop:
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
screen: Dimensions.get('window'),
};
}
getOrientation(){
if (this.state.screen.width > this.state.screen.height) {
return 'LANDSCAPE';
}else {
return 'PORTRAIT';
}
}
getStyle(){
if (this.getOrientation() === 'LANDSCAPE') {
return landscapeStyles;
} else {
return portraitStyles;
}
}
onLayout(){
this.setState({screen: Dimensions.get('window')});
}
render() {
return (
<View style={this.getStyle().container} onLayout = {this.onLayout.bind(this)}>
</View>
);
}
}
}
const portraitStyles = StyleSheet.create({
...
});
const landscapeStyles = StyleSheet.create({
...
});
Finally, I've been able to do so. Don't know the performance issues it can carry, but they should not be a problem since it's only called on resizing or orientation change.
I've made a global controller where I have a function which receives the component (the container, the view) and adds an event listener to it:
const getScreenInfo = () => {
const dim = Dimensions.get('window');
return dim;
}
const bindScreenDimensionsUpdate = (component) => {
Dimensions.addEventListener('change', () => {
try{
component.setState({
orientation: isPortrait() ? 'portrait' : 'landscape',
screenWidth: getScreenInfo().width,
screenHeight: getScreenInfo().height
});
}catch(e){
// Fail silently
}
});
}
With this, I force to rerender the component when there's a change on orientation, or on window resizing.
Then, on every component constructor:
import ScreenMetrics from './globalFunctionContainer';
export default class UserList extends Component {
constructor(props){
super(props);
this.state = {};
ScreenMetrics.bindScreenDimensionsUpdate(this);
}
}
This way, it gets rerendered everytime there's a window resize or an orientation change.
You should note, however, that this must be applied to every component which we want to listen to orientation changes, since if the parent container is updated but the state (or props) of the children do not update, they won't be rerendered, so it can be a performance kill if we have a big children tree listening to it.
Hope it helps someone!
I made a super light component that addresses this issue.
https://www.npmjs.com/package/rn-orientation-view
The component re-renders it's content upon orientation change.
You can, for example, pass landscapeStyles and portraitStyles to display these orientations differently.
Works on iOS and Android.
It's easy to use. Check it out.
React Native also have useWindowDimensions hooks that returns the width and height of your device.
With this, you can check easily if the device is in 'Portrait' or 'Landscape' by comparing the width and height.
See more here
I had the same problem. After the orientation change the layout didn't change.
Then I understood one simple idea - layout should depend on screen width that should be calculated inside render function, i.e.
getScreen = () => {
return Dimensions.get('screen');
}
render () {
return (
<View style={{ width: this.getScreen().width }>
// your code
</View>
);
}
In that case, the width will be calculated at the moment of render.
** I am using this logic for my landscape and portrait Logic.**
** by this if I launch my app in landscape first I am getting the real height of my device. and manage the hight of the header accordingly.**
const [deviceOrientation, setDeviceOrientation] = useState(
Dimensions.get('window').width < Dimensions.get('window').height
? 'portrait'
: 'landscape'
);
const [deviceHeight, setDeviceHeight] = useState(
Dimensions.get('window').width < Dimensions.get('window').height
? Dimensions.get('window').height
: Dimensions.get('window').width
);
useEffect(() => {
const setDeviceHeightAsOrientation = () => {
if (Dimensions.get('window').width < Dimensions.get('window').height) {
setDeviceHeight(Dimensions.get('window').height);
} else {
setDeviceHeight(Dimensions.get('window').width);
}
};
Dimensions.addEventListener('change', setDeviceHeightAsOrientation);
return () => {
//cleanup work
Dimensions.removeEventListener('change', setDeviceHeightAsOrientation);
};
});
useEffect(() => {
const deviceOrientation = () => {
if (Dimensions.get('window').width < Dimensions.get('window').height) {
setDeviceOrientation('portrait');
} else {
setDeviceOrientation('landscape');
}
};
Dimensions.addEventListener('change', deviceOrientation);
return () => {
//cleanup work
Dimensions.removeEventListener('change', deviceOrientation);
};
});
console.log(deviceHeight);
if (deviceOrientation === 'landscape') {
return (
<View style={[styles.header, { height: 60, paddingTop: 10 }]}>
<TitleText>{props.title}</TitleText>
</View>
);
} else {
return (
<View
style={[
styles.header,
{
height: deviceHeight >= 812 ? 90 : 60,
paddingTop: deviceHeight >= 812 ? 36 : 10
}
]}>
<TitleText>{props.title}</TitleText>
</View>
);
}
I have, by far, had the most success with this library: https://github.com/axilis/react-native-responsive-layout
It does what you are asking for and a lot more. Simple Component implementation without hardly any logic like some of the more complex answers above. My project is using Phone, Tablet, and web via RNW - and the implementation is flawless. Additionally when resizing the browser it's truly responsive, and not just on initial rendering - handling phone orientation changes flawlessly.
Example code (Put any components as children of blocks):
<Grid>
<Section> {/* Light blue */}
<Block xsSize="1/1" smSize="1/2" />
<Block xsSize="1/1" smSize="1/2" />
<Block xsSize="1/1" smSize="1/2" />
</Section>
<Section> {/* Dark blue */}
<Block size="1/1" smSize="1/2" />
<Block size="1/1" smSize="1/2" />
<Block size="1/1" smSize="1/2" />
<Block size="1/1" smSize="1/2" />
<Block size="1/1" smSize="1/2" />
</Section>
</Grid>
To give this:
I have written a HoC solution for my expo SDK36 project, it support orientation change and pass props.orientation based on ScreenOrientation.Orientation value.
import React, { Component } from 'react';
import { ScreenOrientation } from 'expo';
export default function withOrientation(Component) {
class DetectOrientation extends React.Component {
constructor(props) {
super(props);
this.state = {
orientation: '',
};
this.listener = this.listener.bind(this);
}
UNSAFE_componentWillMount() {
this.subscription = ScreenOrientation.addOrientationChangeListener(this.listener);
}
componentWillUnmount() {
ScreenOrientation.removeOrientationChangeListener(this.subscription);
}
listener(changeEvent) {
const { orientationInfo } = changeEvent;
this.setState({
orientation: orientationInfo.orientation.split('_')[0],
});
}
async componentDidMount() {
await this.detectOrientation();
}
async detectOrientation() {
const { orientation } = await ScreenOrientation.getOrientationAsync();
this.setState({
orientation: orientation.split('_')[0],
});
}
render() {
return (
<Component
{...this.props}
{...this.state}
onLayout={this.detectOrientation}
/>
);
}
}
return (props) => <DetectOrientation {...props} />;
}
To achieve a more performant integration, I used the following as a superclass for each of my react-navigation screens:
export default class BaseScreen extends Component {
constructor(props) {
super(props)
const { height, width } = Dimensions.get('screen')
// use this to avoid setState errors on unmount
this._isMounted = false
this.state = {
screen: {
orientation: width < height,
height: height,
width: width
}
}
}
componentDidMount() {
this._isMounted = true
Dimensions.addEventListener('change', () => this.updateScreen())
}
componentWillUnmount() {
this._isMounted = false
Dimensions.removeEventListener('change', () => this.updateScreen())
}
updateScreen = () => {
const { height, width } = Dimensions.get('screen')
if (this._isMounted) {
this.setState({
screen: {
orientation: width < height,
width: width, height: height
}
})
}
}
Set any root components to extend from this component, and then pass the screen state to your leaf/dumb components from the inheriting root components.
Additionally, to keep from adding to the performance overhead, change the style object instead of adding more components to the mix:
const TextObject = ({ title }) => (
<View style={[styles.main, screen.orientation ? styles.column : styles.row]}>
<Text style={[styles.text, screen.width > 600 ? {fontSize: 14} : null ]}>{title}</Text>
</View>
)
const styles = StyleSheet.create({
column: {
flexDirection: 'column'
},
row: {
flexDirection: 'row'
},
main: {
justifyContent: 'flex-start'
},
text: {
fontSize: 10
}
}
I hope this helps anyone in the future, and you'll find it to be quite optimal in terms of overhead.
I'm using styled-components, and this is how I re-render the UI on orientation change.
import React, { useState } from 'react';
import { View } from 'react-native';
import { ThemeProvider } from 'styled-components';
import appTheme from 'constants/appTheme';
const App = () => {
// Re-Layout on orientation change
const [theme, setTheme] = useState(appTheme.getTheme());
const onLayout = () => {
setTheme(appTheme.getTheme());
}
return (
<ThemeProvider theme={theme}>
<View onLayout={onLayout}/>
{/* Components */}
</ThemeProvider>
);
}
export default App;
Even if you're not using styled-components, you can create a state and update it on onLayout to re-render the UI.
This is my solution:
const CheckOrient = () => {
console.log('screenHeight:' + Dimensions.get('screen').height + ', screenWidth: ' + Dimensions.get('screen').width);
}
return ( <
View onLayout = {
() => CheckOrient()
} >
............
<
/View>
Note for the case with a pure component. #mridul-tripathi answer works correctly, but if a pure component is used, then probably only parent/top-level component reacting to orientation change is not enough. You will also need to update a pure component separately on orientation change.
All you need is:
import { useWindowDimensions } from 'react-native';
export default function useOrientation() {
const window = useWindowDimensions();
return window.height >= window.width ? 'portrait' : 'landscape';
}
You need useWindowDimensions
This hook re-render component when dimension change and apply styles but Dimensions object can't re-render component and change style, it just work in first render
import { useWindowDimensions } from 'react-native';
then destructure it
const { height, width } = useWindowDimensions();
and final you can do like this
import React from "react";
import { View, StyleSheet, useWindowDimensions } from "react-native";
const App = () => {
const { height, width } = useWindowDimensions();
const isPortrait = height > width;
return (
<View style={isPortrait ? styles.portrait : styles.landscape}>
{/* something */}
</View>
);
};
const styles = StyleSheet.create({
portrait: {},
landscape: {},
});
export default App;
also you can use scale property
const { scale } = useWindowDimensions();
read this document
https://reactnative.dev/docs/usewindowdimensions

Resources