Customizing react native share message based on app - reactjs

I am looking at using ReactNative's share component in my app: https://facebook.github.io/react-native/docs/share#share
Is there a way I can customize the message depending on the app the user chooses to share with?
Like I would want to give a shorter message if the user say shares via twitter as opposed to a longer message for a share via email.
Thanks!

Yes, you can, if the user did share you just need to use result.activityType like this to check if it was shared to WhatsApp for example:
result.activityType === 'net.whatsapp.WhatsApp.ShareExtension'
Check this snack https://snack.expo.io/#neydroid/stack-overflow-test
import * as React from 'react';
import { Alert, Button, Text, View, Share, StyleSheet } from 'react-native';
import { Constants } from 'expo';
import AssetExample from './components/AssetExample';
import { Card } from 'react-native-paper';
export default class App extends React.Component {
onShare = async () => {
try {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
})
if (result.action === Share.sharedAction) {
if (result.activityType && result.activityType === 'net.whatsapp.WhatsApp.ShareExtension') {
// shared with WhatsApp
Alert.alert(result.activityType);
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
// dismissed
}
} catch (error) {
alert(error.message);
}
};
render() {
return (
<View style={styles.container}>
<Button title="Something To Share" onPress={this.onShare}>Share</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
}
});

Related

React native base64 to pdf expo print

I want to print a pdf file on react native mobile app, I receive a base64 code from api and by using it I want to show customer his/her invoice pdf. I tried using Expo Print but I couldnt handle it, I keep getting
Error: Objects are not valid as a React child (found: object with keys {_40, _65, _55, _72}). If you meant to render a collection of children, use an array instead.]
I would appreciate any help!
import React, { Component } from 'react';
import { View, Text, Button, StyleSheet,TouchableHighlight } from 'react-native';
import RNHTMLtoPDF from 'react-native-html-to-pdf';
import * as Print from 'expo-print';
const InvoiceScreen = async({ route, navigation }) => {
const { invoice} = route.params;
const my_uri = "data:application/pdf;base64"+invoice
console.log("DID INVIOCE COMEEE",invoice)
await Print.printAsync(
{uri:my_uri,
width: 595, height: 842 })
return (
<View></View>
);
};
export default InvoiceScreen;
replace your code with this:
const InvoiceScreen = async({ route, navigation }) => {
const { invoice } = route.params;
const my_uri = `data:application/pdf;base64,${invoice}`;
await Print.printAsync({uri:my_uri});
};
export default InvoiceScreen;
Maybe the problem is the data type of the "invoice" parameter, this must be a string which must be the base64 of the pdf file. Reference
If you are using Expo - Managed workflow (Expo CLI / Tool), to view pdf I recommend that you use https://www.npmjs.com/package/rn-pdf-reader-js
I also leave a simple implementation in view:
import React from "react";
import { View, StyleSheet, Dimensions } from "react-native";
import { globalStyles } from "../../constants/globalStyles";
import PDFReader from "rn-pdf-reader-js";
export default function XScreen({ navigation, route }) {
return (
<View style={globalStyles.backGround}>
<PDFReader
source={{
base64: route.params.source,
}}
style={styles.pdf}
/>
</View>
);
}
const styles = StyleSheet.create({
pdf: {
flex: 1,
width: Dimensions.get("window").width,
height: Dimensions.get("window").height,
},
});
Note:
route.params.source =
data:application/pdf;base64,${response.data.data};
response.data.data = string base64 pdf

Using dropdown component in react-navigation throws error when handler is called

I'm trying to use react-navigation with react-native-dropdown in order to have a dropdown in the header to change what is rendered in the view below.
Whenever I try to execute the handler, react-native-dropdown I get the error "undefined is not a function (near'...this.props.data.map')when react-native-dropdown attempts to render again and maps the dropdown using (this.props.data.map((rows, index) => etc.
Below is the code I'm using:
import React, {Component} from "react"
import {Dimensions, ScrollView, StyleSheet, width, View, TouchableOpacity} from "react-native"
import {Images} from "../../theme"
import DropdownMenu from 'react-native-dropdown-menu';
import Pdf from 'react-native-pdf';
import { Header } from "react-native/Libraries/NewAppScreen";
import { connect } from 'react-redux';
import { NavigationActions } from 'react-navigation';
import { drop } from "lodash";
class InformationScreen extends Component {
constructor(props) {
super(props)
var informationScreens = props.global.appConfig.information_screens
var informationScreenTitles = Object.keys(informationScreens)
state = {
informationScreens: informationScreens,
selectedDropdown: informationScreens[0]
}
}
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <DropdownMenu
style={{flex: 1}}
bgColor={'clear'}
tintColor={'#666666'}
activityTintColor={'rgba(2, 122, 255, 1.0)'}
// arrowImg={}
// checkImage={}
// optionTextStyle={{color: '#333333'}}
// titleStyle={{color: '#333333'}}
// maxHeight={300}
handler={(selection, row) => navigation.setParams({'headerTitle': navigation.state.params[selection][row]})}
data={navigation.state.params}
/>
};
};
render() {
return (
<View style={styles.container}>
<Pdf
source={{ uri: "https://someurl.com/dl/sites/default/files/page/2020%20BYU%20Football%20Almanac_3.pdf", cache: true}}
onLoadComplete={(numberOfPages,filePath)=>{
console.log(`number of pages: ${numberOfPages}`);
}}
style={styles.pdf}
/>
</View>
)
}
}
const styles = StyleSheet.create({
image: {
flex: 1,
},
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: 25,
},
pdf: {
flex:1,
width:Dimensions.get('window').width,
height:Dimensions.get('window').height,
}
})
function mapStateToProps(state) {
const global = state.get('global');
return { global };
}
export default connect(mapStateToProps)(InformationScreen);
Ray you were absolutely correct, I figured it out about 5 minutes before you posted.
navigation.state.params was valid and the dropdown would populate, however when I would try to setParams, it would change the format of params to a JSON object instead of an array.
This was remedied by putting my array one JSON object deeper so the object still contained the array after setParams was called. I then called that object in the data.
data={navigation.state.params.informationScreens}
Thank you so much for your help, I'll start using StackOverflow more often.
I suspect this.props.data is either not provided or not an array, so this.props.data.map is undefined, and attempting to invoke it will get you an 'undefined is not a function' error. Is navigation.state.params an array?
If you pass data={navigation.state.params || []} does the issue go away?

Clear Interval when app is in background state in React Native

I would like to know how to clear an Interval whenever my app goes into Background State.
Sometimes when I click the Home button my application is being closed (willUnmount event is not fired) and then the interval is never cleared.
How did you know the interval is never cleared if app closed?(Just curious) If App is being closed, it should be not working at all, isn't it? Only if you have background timer maybe will run?
But I think it should be stopped if you close the app?
I think in your case, you can use AppState from react-native, to detect if app went back to foreground then reset the interval?
import React, {
Component
} from "react";
import {
AppState,
StyleSheet,
Text,
View
} from "react-native";
export default class AppStateExample extends Component {
state = {
appState: AppState.currentState
};
componentDidMount() {
AppState.addEventListener("change", this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener("change", this._handleAppStateChange);
}
_handleAppStateChange = nextAppState => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === "active"
) {
console.log("App has come to the foreground!"); //reset interval here
}
this.setState({
appState: nextAppState
});
};
render() {
return (
<View style = {
styles.container
} >
<Text>
Current state is: {
this.state.appState
}</Text>
</View >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});

React Native save change switch with Async Storage

Im new in React Native, I have a problem with Switch, I want to save changes, dark mode and Switch, when I turn off the app and come back my changes should be saved. When I close the app, my switch came back to first position and dark mode does not work. I know that Im doing something wrong, but I did not mobile app and this is my first time and I dont know how to use AsyncStorage in this App to work this. Can somebody help me solve this problem?
import React, { createContext, useState, useEffect } from 'react';
import { AsyncStorage } from 'react-native';
export const DarkModeContext = createContext();
export default function DarkModeContextProvider(props) {
const [switchMode, setSwitchMode] = useState(false);
useEffect(() => {
let switch1 = switchMode;
AsyncStorage.setItem('switch1', JSON.stringify(switch1));
});
const SwitchThis = () => {
setSwitchMode(!switchMode);
};
return (
<DarkModeContext.Provider
value={{
switchMode,
SwitchThis
}}
>
{props.children}
</DarkModeContext.Provider>
);
}
and next component:
import React, { useState, useContext } from 'react';
import { View, ScrollView, TouchableOpacity, Text, AsyncStorage } from 'react-native';
import { List } from 'react-native-paper';
import BackgroundImage from './BackgroundImage';
import Clock from './Clock';
import TabIcon from './TabIcon';
import AddButton from './AddButton';
import { DarkModeContext } from './app-context';
const HomeScreen = () => {
const { switchMode } = useContext(DarkModeContext);
displayData = async () => {
try {
let switch1 = await AsyncStorage.getItem('switch1', function (err, switch1) {
JSON.parse(switch1)
}
)
return switch1
}
catch (error) {
return error
}
}
return (
<View
style={{
flex: 1,
backgroundColor: !switchMode ? 'white' : '#353535'
}}
>
<BackgroundImage fabButton={<AddButton/>}>
<Clock />
</BackgroundImage>
<ScrollView>
<List.Section>
<List.Subheader style={{ color: !switchMode ? 'black' : 'white' }}>
Task List
</List.Subheader>
<TouchableOpacity onPress={displayData}>
<Text>Click displayData</Text>
</TouchableOpacity>
</List.Section>
</ScrollView>
</View>
);
};
You are importing AsyncStorage from 'react-native' which is deprecated
use #react-native-community/react-native-async-storage
npm i #react-native-community/react-native-async-storage
And on your home screen you are not calling the function displayData() so how is data supposed to be displayed without function call.
and i do suggest making separate functions for writing and reading from async storage, it will help you reduce your code and time.
Like this:
let storeData=(name, obj)=> {
return new Promise((resolve,reject)=>{
let jsonOfItem = JSON.stringify(obj)
AsyncStorage.setItem(name, jsonOfItem).then(r=>resolve(jsonOfItem))
.catch(e=>reject(e))
})
}
let readData=(name)=> {
return new Promise((resolve,reject)=>{
//we want to wait for the Promise returned by AsyncStorage.setItem()
//to be resolved to the actual value before returning the value
AsyncStorage.getItem(name).then(r=> resolve(JSON.parse(r)) )
.catch(e=>reject(e))
})
}
//Now you can just read write easily in async function like this:
let fetchedData = await readData("key")
//and for storing data.
storeData("key",object)

when i use const { myCardStyle } = this.myStyles; at the class below it shows error

I'm learning react native. in my application, for one of the components, when i use this. at const { myCardStyle } = this.myStyles; at the class below it shows error: Possible unhandled Promise Rejection ..., but when i put it without this it works.
const Card = (myProps) => {
const { myCardStyle } = myStyles;
console.log(8 + myProps.children);
return(
<View style={myCardStyle}>
{myProps.children}
</View>
);
};
const myStyles = {
myCardStyle: {
blabla
}
};
const can be accessed without the help of this keyword. Look at the example below. styles can be accessed globally by the class without using this keyword.
this keyword is used when we want to access state or prop objects that are binded to the class. Normally u can bind the finctions using bind keyword
/**
* Sample React Native App
* https://github.com/facebook/react-native
* #flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class VideoExample extends Component {
__click(){
//if u want to access this keyword here
//u have to bind this function
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text onPresss={this._click.bind(this)}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('VideoExample', () => VideoExample);
Try to move const myStyle inside Card method and before
const { myCardStyle } = myStyles
const Card = (myProps) => {
const myStyles = {
myCardStyle: {
blabla
}
};
const { myCardStyle } = myStyles;
console.log(8 + myProps.children);
return(
<View style={myCardStyle}>
{myProps.children}
</View>
);
};
styles are defined outside the class VideoExample so you can't access it using the this.myStyles.
You can directly refer the variable by it's name and if you want to access it in another class you can access it by VideoExample.myStyles.

Resources