Im trying to pick a file (pdf-file) from a module called react-native-file-picker. This works ok, and gaves me name, type, path and uri.
After this, i display the name of the document that i picked in a flatlist.
Now, what i want is to "onPress" of the item in the flatlist, open the document with some pdf viewer or something like that.
I've already tried to use other modules like react-native-view-pdf and react-native-pdf and react-native-pdf-view but i cant access the state of my uri with either of them.
The last one that i used it was react-native-file-viewer and doesn't work very well because it doesn't open the item on press.
This is my actual code.
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Button, TextInput,
Dimensions, FlatList } from 'react-native';
import AsyncStorage from '#react-native-community/async-storage'
import FilePickerManager from 'react-native-file-picker';
import FileViewer from 'react-native-file-viewer';
global.myfunction = function myfunction() {
FilePickerManager.showFilePicker(null, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled file picker');
}
else if (response.error) {
console.log('FilePickerManager Error: ', response.error);
}
else {
this.storeItem(response)
}
});
};
export default class Docs extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: 'Docs',
header: null
}
};
state = {
arr: [],
local: '',
password: '',
obj: null,
count: 1,
image: {},
b64: '',
isModalVisible: false,
pdfuri: null,
};
pdf = () => {
FilePickerManager.showFilePicker(null, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled file picker');
}
else if (response.error) {
console.log('FilePickerManager Error: ', response.error);
}
else {
this.storeItem(response)
this.setState({
pdfuri: response.path
});
}
});
}
toggleModal = (item) => {
this.setState({ isModalVisible: !this.state.isModalVisible, obj: item });
};
storeItem(item) {
try {
//we want to wait for the Promise returned by AsyncStorage.setItem()
//to be resolved to the actual value before returning the value~
console.log(item)
var joined = this.state.arr.concat(item);
console.log('files ', joined)
this.setState({ arr: joined })
AsyncStorage.setItem('files', JSON.stringify(joined));
console.log(this.state.arr)
} catch (error) {
console.log(error.message);
}
}
componentDidMount() {
//Here is the Trick
const { navigation } = this.props;
}
componentWillMount() {
AsyncStorage.getItem('files').then(array => {
item = JSON.parse(array)
item ? this.setState({ arr: item }) : null;
console.log(this.state.arr)
})
}
verpdf() {
const path =
"content://com.android.providers.downloads.documents/document/4183"
FileViewer.open(path, { showOpenWithDialog: true })
.then(() => {
// success
})
.catch(error => {
// error
});
}
render() {
return (
<View style={[styles.container, { marginTop: 20 }]}>
<FlatList
data={this.state.arr}
renderItem={({ item }) => <TouchableOpacity onPress=
{this.verpdf(item)} style={{ marginBottom: 10, marginTop: 10, alignItems: 'center' }}>
<Text>{item.fileName}</Text></TouchableOpacity>}
/>
<Button title='ok' onPress={this.pdf}></Button>
</View>
);
}
}
How should i do this?
Try to change the event handler from
onPress=
{this.verpdf(item)}
to
onPress=
{()=>this.verpdf(item)}
Like #Oleg said, to open a certain item i needed to change the event handler to a arrow function.
onPress = {this.verpdf(item)}
to
onPress= {()=>this.verpdf(item)}
After that i wanted to open a certain item from my flatlist which i did:
verpdf(item) {
const path = item.path
FileViewer.open(path, { showOpenWithDialog: true })
.then(() => {
// success
})
.catch(error => {
// error
});
}
Related
In the react native app I'm retrieving some data from my backend and then want to display it to the app user:
when I log the data I can see that I receive it and stored it properly in the state as an object:
// console.log("received the data: ", this.state.data) ->
received the data: Object {
"a": 48,
"b": "2021-03-29T17:11:51Z",
"c": "",
"d": false
}
But when I try to render that in my view, the screen simply stays empty (no error message):
render() {
// let me check, if the data is really there
Object.entries(this.state.data).map(([key, value]) => {
console.log("key: ", key, "- value: ", value)
})
// output:
// key: a - value: 48,
// key: b - value: 2021-03-29T17:11:51Z,
// key: c - value: ,
// key:d - value: false
return (
<View>
{Object.entries(this.state.data).map(([key, value]) => {
return <View key={key}><Text>{value}</Text></View>
})}
</View>
)
}
I also tried this, but still I receive an empty screen:
render() {
return (
{ this.state.data.map((items, index) => {
return (
<ul key={index}>
{Object.keys(items).map((key) => {
return (
<li key={key + index}>{key}:{items[key]}</li>
)
})}
</ul>
)
})}
)
}
Edit: The full component:
import React from 'react'
import { View, Text } from 'react-native'
import axios from 'axios';
class SuccessScreen extends React.Component {
baseURL = "https://my-backend-server-URL.com/data"
state = {
data: {},
}
componentDidMount() {
this.startGetData();
}
startGetData = () => {
axios.get(this.baseUrl)
.then(response => {
console.log("got the data: ", response.data)
this.state.data = response.data;
})
.catch(function (err) {
//handle error
console.log("error getting data: ", err.message)
return {
type: "REGISTER_USER_FAILED",
payload: null
}
});
};
render() {
console.log("This log will show up")
return (
<View>
{this.state.vehicleData && Object.entries(this.state.vehicleData).map(([key, value]) => {
console.log("this log never shows up... key: ", key) // these logs don't not show up
return <View key={key}><Text>{value}</Text></View>
})}
</View>
)
}
}
export default SuccessScreen;
Wait for data to be defined, Try this:
return (
<View>
{this.state.data && Object.entries(this.state.data).map(([key, value]) => {
return <View key={key}><Text>{value}</Text></View>
})}
</View>
Edit:
Don't mutate this.state.data = response.data that way, use the setState:
this.setState({ data: response.data });
https://reactjs.org/docs/faq-state.html#what-does-setstate-do
i am using react-native-html-to-pdf package to create a pdf file i want to pass the api response from react-native to html and receive the data from html. the options available for this npm package is very minimum
There is no options in the package so that i can use it, can someone help me with this ?
Below is my code.
import React, { Component } from 'react';
import { Text, TouchableOpacity, View, StyleSheet, Image, PermissionsAndroid, Platform,} from 'react-native';
import RNHTMLtoPDF from 'react-native-html-to-pdf';
import htmlContent from './htmlContent'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
apiData: [],
filePath: ''
}
}
askPermission() {
var that = this;
async function requestExternalWritePermission() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: 'External Storage Write Permission',
message:
'App needs access to Storage data in your SD Card ',
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
that.createPDF();
} else {
alert('WRITE_EXTERNAL_STORAGE permission denied');
}
} catch (err) {
alert('Write permission err', err);
console.warn(err);
}
}
if (Platform.OS === 'android') {
requestExternalWritePermission();
} else {
this.createPDF();
}
}
componentDidMount(){
fetch(`http://API`)
.then((response) => response.json())
.then((responseJson) => {
**console.log("DATA", responseJson) // NEED TO SEND THIS DATA TO "HTML"**
this.setState(() => ({
apiData: responseJson
}))
})
}
async createPDF() {
let options = {
html:htmlContent, // API DATA SHOULD BE SENT TO HTML
fileName: 'RTT Report',
directory: 'docs',
width: 800,
};
let file = await RNHTMLtoPDF.convert(options);
console.log(file.filePath);
this.setState({filePath:file.filePath});
}
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={this.askPermission.bind(this)}>
<View>
<Image
//We are showing the Image from online
source={{
uri:
'https://raw.githubusercontent.com/AboutReact/sampleresource/master/pdf.png',
}}
//You can also show the image from you project directory like below
//source={require('./Images/facebook.png')}
style={styles.ImageStyle}
/>
<Text style={styles.text}>Create PDF</Text>
</View>
</TouchableOpacity>
<Text style={styles.text}>{this.state.filePath}</Text>
</View>
);
}
}
In createPDF method :
// html:htmlContent, // API DATA SHOULD BE SENT TO HTML
html: this.state.apiData // <-- you have stored your html in the state
EDIT:
Probably I was too fast answering, now I think I got your point , here you have an example :
// html: '<h1>PDF TEST</h1>', <-- example from react-native-html-to-pdf
const exampleData = [
{
title: "Element title",
content: "Element content"
},
{
title: "Other title",
content: "Other element content"
}
]
function generateHTML () {
const data = exampleData
// const data = this.state.apiData // <-- in your case
let htmlContent = '<html><body>'
htmlContent += data.map(entry => {
return `<h5>${entry.title}</h5> <br /> <p>${entry.content}</p>`
}).join(' ')
htmlContent += '</body></html>'
return htmlContent
}
I'm working on a React-Native project with REST APis, and I've currently got an invariant violation error. I've experienced this before, but I can't quite figure out what is causing it and how to fix it. If someone could point me in the right direction, I would really appreciate it! The full error is pictured below, and appears to be referencing a number of tags in the code, so I'm unsure exactly where it is originating. Thank you for reading, and thanks in advance!
The code is here:
import React, { Component } from 'react'
import { View, Text, Image, StyleSheet, FlatList} from 'react-native';
import * as Font from 'expo-font';
import styled from 'styled-components';
import dimensions from '../components/ScreenSize';
import colours from '../components/Colours';
import { Audio } from 'expo-av';
import { TouchableHighlight } from 'react-native-gesture-handler';
const client_id = {Client_ID}
const client_secret = {Client_Secret}
const item = ({item}) => (
<View style={{ flex:1, flexDirection: 'column', margin:1}}>
<TouchableHighlight onPress={() => this.fetchTracks(item.id)}>
<View>
<Text>{item.name}</Text>/>
</View>
</TouchableHighlight>
</View>
)
export default class HomeScreen extends React.Component {
state={
fontsLoaded:false,
}
async componentDidMount() {
await Font.loadAsync({
'montserrat-regular': require('../assets/fonts/Montserrat/Montserrat-Regular.ttf'),
'montserrat-light': require('../assets/fonts/Montserrat/Montserrat-Light.ttf'),
'montserrat-semibold': require('../assets/fonts/Montserrat/Montserrat-SemiBold.ttf'),
'montserrat-bold': require('../assets/fonts/Montserrat/Montserrat-Bold.ttf'),
}
).then(() => this.setState({ fontsLoaded:true }))
this.getToken();
this.setAudio();
}
constructor (props) {
super(props)
this.playbackInstance=null;
this.state = {
playing:false,
token: '',
DATA:[],
};
}
setAudio=() => {
Audio.setAudioModeAsync({
allowsRecordingIOS:false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false,
});
}
componentDidCatch(error, info)
{
console.log(error, info.componentStack);
}
getToken = async() =>
{
try
{
const getspotifytoken = await fetch("https://accounts.spotify.com/api/token",
{
method:'POST',
body: `grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const spotifytoken = await getspotifytoken.json();
this.setState({
token: spotifytoken.access_token
});
console.log(this.state.token);
}
catch(err)
{
console.log("Error fetching data", err);
}
}
search = async () => {
try
{
console.log("Searching: mood")
const spotifyApiCall = await fetch(`https://api.spotify.com/v1/browse/categories/mood/playlists?`, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${this.state.token}`,
"Content-Type":'application/json'
}
})
const spotify = await spotifyApiCall.json();
console.log("Items", spotify);
this.setState({
DATA: spotify.playlists.items,
})
}
catch (err)
{
console.log("Error fetching data", err);
}
}
fetchTracks = async (playlistId) => {
console.log('Playlist ', playlistId)
try
{
const getplaylist = await fetch(`https://api.spotify.com/v1.playlist/${playlistId}`,
{
method:'GET',
headers: {
Accept:"application/json",
Authorization:`Bearer ${this.state.token}`,
"Content-Type":"application/json"
}
});
const playlist = await getplaylist.json();
console.log('music ', playlist.tracks.items[0].preview_url);
}
catch (err)
{
console.log("Error fetching data ", err);
}
}
async _loadNewPlaybackInstance(playing, track) {
if(this.playbackInstance != null)
{
await this.playbackInstance.unloadAsync();
this.playbackInstance.setOnPlaybackStatusUpdate(null);
this.playbackInstance = null;
}
const source = {uri: track};
const initialStatus = {
shouldPlay: true,
rate: 1.0,
shouldCorrectPitch: true,
volume: 1.0,
isMuted: false
};
const {sound, status} = await Audio.Sound.createAsync(
source.initialStatus);
this.playbackInstance=sound;
this.playbackInstance.setIsLoopingAsync(false);
this.playbackInstance.playAsync();
if (this.state.selected === playlistId) {
console.log("Playing, so stop");
this.setState({selected:null});
this.playbackInstance.pauseAsync();
return;
}
this.setState({ selected:playlistId});
this._loadNewPlaybackInstance(true, playlist.tracks.items[0].preview_url);
}
render() {
if(!this.state.fontsLoaded ) {
return null
}
return (
<Container>
<Titlebar>
<Title>Music</Title>
</Titlebar>
<HeaderBar2>
<TouchableHighlight onPress={() => this.search()}>
<Header2>Playlists for your Mood</Header2>
</TouchableHighlight>
</HeaderBar2>
<View style={styles.MainContainer}>
{
this.state.DATA.length == 0 &&
<Text style={{padding:10, color:'#D3D3D3'}}/>
}
<FlatList
data = {this.state.DATA}
renderItem={item}
keyExtractor = {item.id}
numColumns={2}
extraData = {this.state}
/>
</View>
</Container>
);
}
}
I think u just have a little typo ..
check this line: <Text>{item.name}</Text>/>
change the last Text to </Text>
I made a CameraComponent.js having function launchCamera(). I am calling CameraComponent.js in my BottamTab navigation. I had make simple button to launch camera by calling launchCamera(). But i want to launch camera directly when component call in BottamTab navigation just like in whatsapp moving topTab to left. I tried to call function in constructor instead of ComponentWillMount(as it is removed in react native). But nothing work. Here is my below code
export default class CameraComponent extends React.Component {
constructor(props) {
super(props);
launchCamera();
this.state = {
filePath: {},
};
}
launchCamera = () => {
let options = {
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.launchCamera(options, response => {
// console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
let source = response;
// You can also display the image using data:
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
filePath: source,
});
}
});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.launchCamera.bind(this)} >
<Text>Launch Camera</Text>
</TouchableOpacity>
</View>
);
}
}
I am new in react native I am trying to render the count of unread notification for that I called my API in HOC it is working fine for initial few seconds but after that, I started to get the below error
func.apply is not a function
below is my code
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Modal, View } from "react-native";
import { themes } from "./constants";
import { AsyncStorage } from "react-native";
export default (OriginalComponent, animationType) =>
class extends Component {
static propTypes = {
handleFail: PropTypes.func,
theme: PropTypes.string,
visible: PropTypes.bool
};
state = {
modalVisible: true
};
static getDerivedStateFromProps({ visible }) {
if (typeof visible === "undefined") {
setInterval(
AsyncStorage.getItem("loginJWT").then(result => {
if (result !== null) {
result = JSON.parse(result);
fetch(serverUrl + "/api/getUnreadNotificationsCount", {
method: "GET",
headers: {
Authorization: "Bearer " + result.data.jwt
}
})
.then(e => e.json())
.then(function(response) {
if (response.status === "1") {
if (response.msg > 0) {
AsyncStorage.setItem(
"unreadNotification",
JSON.stringify(response.msg)
);
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}
})
.catch(error => {
alert(error);
// console.error(error, "ERRRRRORRR");
});
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}),
5000
);
return null;
}
return { modalVisible: visible };
}
handleOpenModal = () => {
this.setState({ modalVisible: true });
};
handleCloseModal = () => {
const { handleFail } = this.props;
this.setState({ modalVisible: false }, handleFail);
};
render() {
const { modalVisible } = this.state;
const { theme } = this.props;
return (
<View>
<Modal
animationType={animationType ? animationType : "fade"}
transparent={true}
visible={modalVisible}
onRequestClose={this.handleCloseModal}
>
<View style={themes[theme] ? themes[theme] : themes.transparent}>
<OriginalComponent
handleCloseModal={this.handleCloseModal}
{...this.props}
/>
</View>
</Modal>
</View>
);
}
};
I have not used getDerivedStateFromProps but, according to the docs, it is called on initial component mount and before each render update.
Thus your code is creating a new interval timer on each update without clearing any of the earlier timers, which could be causing a race condition of some sort.
You may want to consider using the simpler alternatives listed in the docs, or at a minimum, insure that you cancel an interval before creating a new one.