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
Related
I have video that I'd like to present as preview_video image/thumbnail before a user clicks on them for the full video. Is there a RN component to do this?
I have this code:
import { Video } from 'expo-av';
import VideoPlayer from 'expo-video-player';
import * as React from "react";
import {View} from "react-native";
import Header from "../../components/header/Header";
export default function VideoPlayerComponent(props) {
const { url } = props.route.params;
return (
<View>
<Header
title="Video"
goBack
/>
<VideoPlayer
style={{height:550}}
videoProps={{
shouldPlay: true,
resizeMode: Video.RESIZE_MODE_CONTAIN,
source: {
uri: url,
},
}}
/>
</View>
);
}
Seems you can try this component: https://docs.expo.dev/versions/latest/sdk/video-thumbnails/
const generateThumbnail = async () => {
try {
const { uri } = await VideoThumbnails.getThumbnailAsync(
'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4',
{
time: 15000,
}
);
setImage(uri);
} catch (e) {
console.warn(e);
}
Then just include a condition when the video component is in its paused state, the thumbnail should be displayed with a higher zIndex.
Like describe here: react native video display thumbnail before video is played
I have a project where i need to map specific areas of an image, for that i'm trying to use react-img-mapper, but when i try to run the example code, the only think that shows is a blanck screen, react do not log any erros. What am i doing wrong ?
import React from 'react';
import ImageMapper from 'react-img-mapper';
const Mapper = props => {
const URL = 'https://raw.githubusercontent.com/img-mapper/react-docs/master/src/assets/example.jpg';
const MAP = {
name: 'my-map',
// GET JSON FROM BELOW URL AS AN EXAMPLE
areas: 'https://raw.githubusercontent.com/img-mapper/react-docs/master/src/assets/example.json',
};
return <ImageMapper src={URL} map={MAP} />
}
export default Mapper;
I have a basic flat list of products that are getting rendered from a products array. Im using react navigation to navigate to a product detail screen but trying to think of the best way to get the active selected product so I can display the product information in the product detail page.
My Approach: I thought just use a hook to provide the active product and I tried that but for some reason I am not getting the proper state provided in the product detail page.
Getting the error: "TypeError: null is not an object (evaluating 'product.title')"
By the way for now I'm trying to avoid using redux as my school project is due tomorrow and also trying to learn hooks.
EDIT: Hmm I see now I can also use Route params. I think I would still really like to understand what is going on with my current hooks approach.
Product Card Component
import React, { useState, useEffect } from "react";
import {
View,
ImageBackground,
Text,
Pressable,
StyleSheet,
Button,
Dimensions,
ScrollView,
RefreshControl,
SafeAreaView,
Image,
FlatList,
TouchableOpacity,
} from "react-native";
import { useQuery, gql } from "#apollo/client";
import Amplify, { Auth } from "aws-amplify";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import { useNavigation, NavigationContainer } from "#react-navigation/native";
import useProduct from "../hooks/useProduct";
function ProductCard({ item }) {
const navigation = useNavigation();
const { setActiveProduct } = useProduct();
const imgUrl = "http://192.168.1.252:3000" + item.media[0].URLs.thumbnail;
const imgUrl2 = imgUrl.replace("thumbnail", "large");
return (
<TouchableOpacity
style={styles.buttonContainer}
onPress={() => {
setActiveProduct(item);
navigation.navigate("Product Detail");
}}
>
<View style={styles.view}>
<Image
style={styles.productImage}
source={{
uri: imgUrl2,
}}
/>
</View>
</TouchableOpacity>
);
}
export default ProductCard;
const styles = StyleSheet.create({
buttonContainer: {
flex: 0.5,
margin: 5,
backgroundColor: "white",
},
view: {
flex: 1,
display: "flex",
flexDirection: "column",
height: 200,
},
productImage: {
width: "100%",
height: "70%",
},
description: {
width: "100%",
height: "60%",
},
});
Product Detail Page
import React, { useState, useEffect } from "react";
import {
View,
ImageBackground,
Text,
Pressable,
StyleSheet,
Button,
Dimensions,
ScrollView,
RefreshControl,
SafeAreaView,
Image,
FlatList,
TouchableOpacity,
} from "react-native";
import useProduct from "../../hooks/useProduct";
function ProductDetailScreen() {
const { product } = useProduct();
if (!product) {
return (
<View>
<Text>{product.title}</Text>
</View>
);
}
return (
<View>
<Text>{product.title}</Text>
</View>
);
}
export default ProductDetailScreen;
useProduct hook to manage my active product state
import React, { useState } from "react";
function useProduct() {
const [product, setProduct] = useState(null);
setActiveProduct = (newProduct) => {
setProduct(newProduct);
};
return { product, setActiveProduct };
}
export default useProduct;
useProduct() returns separate state objects to both components. Try using product inside ProductCard. You will see the product updated in ProductCard component. But this product is not the same that is returned to ProductDetailScreen. Both components get separate state objects.
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)
first I was trying to get my .png icons from the api which I did it but my browser renders it as image since I used the tag , or even if I want to import from my local system, it still is rendered as image file using tag...
you can use the below-mentioned solution. As its created a separate component for Icon like
import React, { PropTypes } from "react";
const Icon = props => {
const styles = {
img: {
width: `${props.size}`,
height: `${props.size}`
}
};
return <img style={styles.img} src={props.icon} />;
};
Icon.propTypes = {
size: PropTypes.string,
icon: PropTypes.string.isRequired
};
Icon.defaultProps = {
size: 32
};
export default Icon;
More details Here