0

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.

Hols
  • 361
  • 1
  • 5
  • 21

2 Answers2

1

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

barak m.
  • 606
  • 5
  • 4
  • Thanks for your helpful response @barak.m. My app is using Redux so I implemented the call to Device.IsTablet() in an action which I then call in the first screen of the app. It is working fine even tho I did notice that the very first load returns a promise as opposed to the expected true/false. When I read the state in other views or on subsequent reloads (I am using Redux Persist) it does have the expected value tho. – Hols Sep 25 '19 at 18:34
  • 1
    @Hols Glad to help! The first call to ` DeviceInfo.isTablet() ` will always return a Promise. That part you can't change, but you can work around it. The idea is re-render after the Promise returns with a true/false value. So the first render will not know the value of isTablet, but all subsequent renders will. This is a common challenge with the React approach, you have to accept that things can happen Asynchronously and make sure your UI shows the user something appropriate (like a loading indicator, etc.) – barak m. Sep 28 '19 at 18:58
0

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;
`
Dave Islas
  • 26
  • 1