React Native: How to Determine if Device is iPhone or iPad - react-native

I know with React Native that we have the ability to determine whether iOS or Android is being run using the Platform module, but how can we determine what device is being used on iOS?

As of 9.02.2018 there is also
import { Platform } from 'react-native'
Platform.isPad // boolean
Mind that (as of now) it has no android counterpart.
IOS https://github.com/facebook/react-native/blob/master/Libraries/Utilities/Platform.ios.js#L23
Android https://github.com/facebook/react-native/blob/master/Libraries/Utilities/Platform.android.js (no isPad!)

Simplest approach will be using the aspect ratio. The code will be:
import { Dimensions } from 'react-native';
const {height, width} = Dimensions.get('window');
const aspectRatio = height/width;
if(aspectRatio>1.6) {
// Code for Iphone
}
else {
// Code for Ipad
}
Aspect ratio of iPad is 4:3 (1.334) and aspect ratio of iPhone is 16:9 (1.778)
Make sure to check if you are on an iOS device using Platform.OS === 'ios' method before applying the above logic.

if using TypeScript, there is a type in react-native called PlatformIOSStatic, you need to force-cast Platform to PlatformIOSStatic.
import { Platform, PlatformIOSStatic } from 'react-native'
if (Platform.OS === 'ios') {
const platformIOS = Platform as PlatformIOSStatic
console.log(platformIOS.isPad)
console.log(platformIOS.isTVOS)
}
The interface design here is pretty bad, hope RN team would improve it.

If you're looking for a way to do that without including 3rd party libraries (like react-native-device-info) you can also do:
import { NativeModules } from 'react-native';
const { PlatformConstants } = NativeModules;
const deviceType = PlatformConstants.interfaceIdiom;
deviceType can take the values: phone, pad, tv, carplay and unknown.

You can roughly determine what iOS device is being used without any external dependencies... First query Platform.OS then the Dimensions module allows you to query the device for screen dimensions which can be translated to devices: http://iosres.com/

I used isTablet() to detect ipad with iphone
https://github.com/rebeccahughes/react-native-device-info
import { isTablet } from 'react-native-device-info';
if (isTablet()) {
// try something
}

You should be able to get that information from the module react-native-device-info
https://github.com/rebeccahughes/react-native-device-info

Both will return true in iPad if you have set iPad configuration in the target of the project in code in general otherwise it will return flase.
import { isTablet } from 'react-native-device-info';
isTablet()
OR
import { Platform } from 'react-native'
Platform.isPad // boolean

$ npm install react-native-device-detection --save
$ react-native link
if(Device.isIos) {
}
if(Device.isTablet) {
}

I use this solution: https://stackoverflow.com/a/48709199/2400373
My solution final is this:
import { Platform } from "react-native";
Dispositivo() {
if (Platform.isPad == true) {
return(
<Text>test</Text>
)
}
Then I call this function:
{this.Dispositivo()}

A good solution by #Maxwelll.
A more accurate approach would be to measure the screen ratio.
All iPhones are 16:9, all iPads are 3:4.

Related

Is it possible to load particular screen in react native without navigation

I am using react native 0.64, I want to load my profile screen from home screen without using navigation. Is it possible? Can anyone help?
You should use a state for represent home or profile.
for ex:
function HomeScreen() {
const [screenName, setScreenName] = useState('home')
if (screenName == 'profile') {
return <ProfileScreen/>
}
return {
...
// handling the event to go Profile screen
setScreenName('profile')
...
}
}

Expo React Native - How come returning null on App.js initialization function is good behaviour?

This is mainly a comprehension problem:
Considering the following expo docs, which aren't explaining what is going on under the hood,
import { useFonts } from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync();
export default function App() {
const [fontsLoaded] = useFonts({
'Inter-Black': require('./assets/fonts/Inter-Black.otf'),
});
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
}
return (
// Your app tree there.
);
}
What is going on here from my understanding is that you prevent the splashscreen from going away while you retrieve certain assets, like fonts.
When you do have your assets, you make the splashscreen go away and you launch your app by returning your components' tree.
The part I don't understand is why is it ok to return null if the fonts don't get loaded?
Since it is the initialization function, my mind want to think that if you return null to it, your app doesn't start and the user will be left wondering why...
Is there an explanation, a logic behind the hood actually refreshing something to recheck until it is ok and the assets are indeed loaded or something I don't know?
I know I have the case of my app not starting correctly every time right now and I'm wondering if this "return null" on the App.js function could be the culprit.

Fetching Data From Server Using iOS Device in React Native

I have just started learning React Native and development for mobile devices. One of the things I've tried is using fetch API to get data from http://jsonplaceholder.typicode.com/posts
The App.js file is given below:
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
export default function App() {
const [firstLoad, setLoad] = React.useState(true);
const [data, upDateData] = React.useState([]);
let isLoading = true;
async function sampleFunc() {
let response = await fetch("https://jsonplaceholder.typicode.com/posts");
let body = await response.json();
upDateData(body);
}
if (firstLoad) {
sampleFunc();
setLoad(false);
}
if (data.length > 0) isLoading = false;
const posts = data.map(post => (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
));
return (
<View style={styles.container}>
{isLoading ?
<Text>Loading</Text> :
<Text>{posts}</Text>
}
</View>
);
}
Nothing fancy is going on here, just making an https request to the server to get posts. While the data is being transferred, the Loading label is being displayed, after that, all fetched posts are rendered on the page.
I am using Expo, and everything works fine when I run it in the browser, but when I scan the QR code, Expo app opens, the Loading message is displayed for a couple of seconds, and then the app crashes.
I may be doing something here that is typical of regular React and is not used in React Native. It is just strange that it would work on my computer and not the phone. Any suggestions would be greatly appreciated. Thank you in advance!
You cannot have text outside of Text components in react-native.
In your example, in the post function, you use the h1 and p tags, which are not supported by react-native.
The fix here is to make sure that those texts are inside Text components, you can have styling set to those to make them look closer to what you want.
You can refer the docs on how to create custom styles.
const posts = data.map(post => (
<View>
<Text>{post.title}</Text>
<Text>{post.body}</Text>
</View>
));
To debug similar issues in the future, you should be getting a red flashing screen with the exception. (Maybe it doesn't appear when running on Expo)

how to disable YellowBox in react-native totally in a native way ? not in JavaScript

I know console.disableYellowBox = true could be answer. But I want ban it with all my control because my App has multiple package and I do not want to use console.disableYellowBox = true in every package.
is there any way to achieve this by set a config in shaking bar ?
I tried with the new React version replacing the import to:
import { LogBox } from "react-native";
and adding this line inside App.js
LogBox.ignoreAllLogs();
And it's working good for me.
You have multiple way's in doing that, which is not recommended since you want to know what's causing these warnings and sometimes it's important informations you need to know, here is some of the ways you can do
Warnings will be displayed on screen with a yellow background. These
alerts are known as YellowBoxes. Click on the alerts to show more
information or to dismiss them.
As with a RedBox, you can use console.warn() to trigger a YellowBox.
YellowBoxes can be disabled during development by using
console.disableYellowBox = true;
using ignore
console.ignoredYellowBox = ['Warning: Each', 'Warning: Failed'];
ignoredYellowBox allows you to ignore certain warnings as you can see in the example above.
using disableYellowBox
console.disableYellowBox = true;
disableYellowBox allows you to disable it completely from your app.
however both these ways you need to use inside App.js before you render you app.
example:
import React, { Component } from "react";
import { View } from "react-native";
//console.disableYellowBox = true;
//OR
//console.ignoredYellowBox = ['Warning: Each', 'Warning: Failed'];
export default class App extends Component {
render() {
return (
<View>
{/*Your Code will be here*/}
</View>
);
}
}
Take a look at Debugging React Native to learn more about YellowBox
// RN >= 0.52
import {YellowBox} from 'react-native';
YellowBox.ignoreWarnings(['Warning: ReactNative.createElement']);
// RN < 0.52
console.ignoredYellowBox = ['Warning: ReactNative.createElement'];

React Native: How can I use the DeviceInfo isTablet() method to conditionally apply a style to an element?

I am trying to adapt the design of my app to tablet and one way to detect if the app is running on a tablet is by using the DeviceInfo module in particular the isTablet() method. How can I use this method to conditionally apply styles to an element?
Here is what I am trying to do at the moment:
import { checkIfDeviceIsTablet } from './helper-functions';
<View style={[styles.wrapper, checkIfDeviceIsTablet() === true ? styles.wrapperTablet : {}]}>
{contents}
</View>
The checkIfDeviceIsTablet() function is as follows:
import DeviceInfo from 'react-native-device-info';
function checkIfDeviceIsTablet() {
DeviceInfo.isTablet().then(isTablet => {
return isTablet;
});
}
The issue is that when the component loads the checkIfDeviceIsTablet() method returns a promise as opposed to the expected true/false value and so the conditional styles are not applied when the app is run on a tablet. I tried turning the function into an async/await format with a try/catch but the result is the same.
I would use React Native's own Platform.isPad function but the app must also work on Android.
Any help is appreciated.
I would recommend calling DeviceInfo.isTablet() only once at the beginning of your app. You can store the result globally, and then later on you can check the type without having to deal with async promises.
To store the type globally, your options are:
A global variable
React's Context API
A static property on a class (if using ES6+)
Some sort of global state management solution like Redux
You still have to deal with the initial async problem, since the first call to DeviceInfo.isTablet() will return an async promise.
I'd recommend looking into React's Context API.
Here's a rough example:
render() {
return (
<DeviceInfoContext.Consumer>
{ ({ isTablet }) => (
<Text>Is this a tablet? {isTablet}</Text>
) }
</DeviceInfoContext.Consumer>
)
}
And your DeviceInfoContext class would look something like this:
class DeviceInfoContext extends React.Component {
state = {
isTablet: false
}
componentDidMount() {
Device.IsTablet().then(result => this.setState({ isTablet: result }))
}
render() {
return (
this.props.children({ isTablet: this.state.isTablet })
)
}
}
This is just a rough example. You can learn more about the Context API in the docs
Me too had some troubles with the breaking changes of react native 0.5xx to 0.6xx. The library for device detection change it structure to promises. A paintful.
This library save the day, the installation and use is very easy.
https://github.com/m0ngr31/react-native-device-detection
import { isTablet } from 'react-native-device-detection;
// isTablet is a boolean. Return false o true immediately
//So ...
import styled from 'styled-components/native';
import theme from 'styled-theming';
import { isTablet } from 'react-native-device-detection';
const CoverPageDateText = styled.Text`
font-size: ${isTablet ? 23 : 17};
color: gray;
padding-bottom: 9;
`