how to read file from local storage? - react-native

I am uploading image to device's local storage (Android), task is doing with success , now
I am facing issues when I try to read the file from the local storage , it pops up errors
saying that :
invariation Violation object are not valid React child
here is my code to upload the image :
let dirs = RNFetchBlob.fs.dirs;
RNFetchBlob.fs.exists(dirs.PictureDir + "/myfolder")
.then((exist) => {
//console.log(`file ${exist ? '' : 'not'} exists`);
if (!exist) {
try {
const fs = RNFetchBlob.fs;
/
RNFetchBlob.fs.mkdir(dirs.PictureDir + "/myfolder")
.then(() => {
let base64Str = data;
fs.writeFile(dirs.PictureDir + "/myfolder/" + imageName, base64Str, 'base64')
.then(() => {
RNFetchBlob.fs.scanFile([{
path: dirs.PictureDir + "/myfolder/",
mime: 'jpeg/jpg'
}]);
}).catch(() => {
alert("error");
})
here is the path to my image
const path =
dirs.PictureDir+"/myfolder/1718179779c718ba84098b90f6061816fba9f.jpg"
and here my code to access that image , could you please help
<ScrollView keyboardShouldPersistTaps="handled">
<View style={styles.containerWithMargin} >
{RNFetchBlob.fs.readFile(path, 'base64') .then( (data) =>
<Avatar
medium
onPress={this.onSelectPostImage.bind(this)}
source={{uri : data}}
/>
)}
</View>

RNFetchBlob.fs.readFile returns a promise, anything asynchronous should be in ComponentDidMount and from there you can use setState to set imageUrl for example, then in jsx you will have something like this
<View style={styles.containerWithMargin} >
{imageUrl &&
<Avatar
medium
onPress={this.onSelectPostImage.bind(this)}
source={{uri : imageUrl}}
/>
}
</View

Related

React Native Workflow, handle 429 erros and data

im looking for a bit of guideness here, im working on a RN app with redux and everytime i enter a new screen on the app, must likely i have a "callinitialData" function inside my useEffect(), using axios to fetch api data to be dispatch() to the redux state.
Everything works but whenever i jump from screen to screen to fast, sometimes i get a 429 error of to many request, so i just setup the redux-persist hoping that would help reduce the amount of request,in my mind thinking that if my api data is equal to my local data, that request wouldnt be necessary to be made.
However it stays the same so i was thinking what would be the best aproach here, on login try to fetch all the data at once > store it at asyncstorage and redux, and fetch that on each screen ?
how would i be able then, if i fetch all the data on login, receive the new data sets from the api in real time?
App functionality -
Edit Profile (img, pass, email, name)
Data Forms (requeast X, submit data, edit forms)
Chat by contacts / create Group chat
Code Example
const ChatScreen = ({ auth: { user }, getChatContacts, chat: { contacts }, navigation }) => {
useEffect(() => {
getChatContacts();
}, []);
const onChatUser = async (_id, name, roomID) => {
console.log(_id, name, roomID, contacts.payload.clone)
navigation.navigate( "Message", {
_id, name, chatRoomId: roomID, allUsers: contacts.payload.clone
});
}
const renderItem = ({ item , index } ) => {
let userName = "";
item.users.map((users, index) => {
let idToCheck = users.toString() !== user._id.toString() ? users : false;
if (idToCheck) {
let getOneUser = contacts.payload.clone.find(x => x._id === idToCheck);
userName += "" + getOneUser.name + ", ";
}
})
return (<TouchableOpacity key={item._id} onPress={() => onChatUser(item._id, item.name, item.roomID)}>
<View style={styles.chatContainer}>
<FontAwesome name="user-circle-o" size={50} color="#000000"/>
<Text style={styles.chatTitle}>{ ((userName).length > 32) ?
(((userName).substring(0,32-3)) + '...') :
userName }</Text>
<FontAwesome name="angle-right" size={25} color="#000000"/>
</View>
</TouchableOpacity>)
};
return (
<SafeAreaView style={styles.container}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
placeholder="Search friend"
style={styles.chatsearch}
/>
{contacts ?
(<FlatList
data={contacts.payload.allContact}
renderItem={(item, index) => renderItem(item, index)}
keyExtractor={item => item.id}
style={styles.FlatListContainer}
/>) : (<Text style={styles.FlatListContainer}></Text>)
}
</SafeAreaView>
);
}
const styles = StyleSheet.create({});
ChatScreen.propTypes = {
isAuthenticated: PropTypes.bool,
auth: PropTypes.object,
};
const mapStateProps = state => ({
auth: state.auth,
chat: state.chat
});
export default connect(mapStateProps, {getChatContacts} )(ChatScreen);
Redux Action
export const getChatContacts = () => async dispatch => {
const config = {
header: {
"Content-Type": "application/json"
}
}
try {
const res = await axios.get(API_LINK +"/users/getChatContacts",);
dispatch({
type: GET_CONTACT_CHAT,
payload: res.data
});
} catch (err){
console.log(err)
dispatch({
type: ERROR_FAMILY_PARENT,
payload: { msg: err.response, status: err.response}
});
}
};

AsyncStorage use boolean from Promise

hi i'm new on react native and i have a issue with asyncStorage. I want to store the cache state in my pdf screen. The cache is a parameter of the source and handle only boolean. I made an onPress which change a state and store it in my localstorage, it works and when i console.log my getItem it shows true or false too it works too. But here is my problem. Now i want to just use the true or the false from this getItem because the parameter cache can handle boolean only. The best i could get on my search was Promise Boolean for my function. So if you could help me it'll be incredible because i really don't know. Thank you a lot and sorry for my English.
Here's my code //
export class Liste extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
navigation : props.navigation,
route: props.route,
selectedIndex : this.selectedIndex,
page : this.page,
numberOfPages : this.numberOfPages,
filePath : [],
cache : false,
};
}
saveCache() {
AsyncStorage.setItem('cache', JSON.stringify(this.state.cache));
console.log(`store ${this.state.cache}`);
}
async getCache () {
const ta = await AsyncStorage.getItem('cache', (value) => {
JSON.parse(value)
})
console.log(ta)
}
navigateBack = () => {
this.state.navigation.goBack();
};
BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={this.navigateBack}/>
);
render() {
const {files} = this.state.route.params;
const cache = this.state.cache;
const bool = this.getCache();
return (
<>
<TopNavigation style={{ borderWidth: 1 }} title='Mes Articles' alignment='center' accessoryLeft={this.BackAction} />
<ViewPager
selectedIndex={this.state.selectedIndex}
onSelect={ index => this.setState({ selectedIndex: index })}>
{files.map((file, i) =>
<Layout style={styles.tab} level='2'>
<Text>{file.filename}</Text>
<Text>Article: {i + 1} / {files.length} page: {this.state.page} / {this.state.numberOfPages}</Text>
<View>
<TopNavigationAction icon = {emailIcon} onPress={() => Share.open({ title: 'Pdf file', message: `bonjour voici l'article pdf ${file.filename}`, url: `file:///${this.state.filePath[i]}`, subject: `Article Pdf ${file.filename}` })} status='Partager'>
Partager
</TopNavigationAction>
<TopNavigationAction icon = {pin} onPress ={() => this.saveCache(cache === true ? this.setState({cache : false}) : this.setState({cache : true}))} status='Partager'>
Partager
</TopNavigationAction>
<TopNavigationAction icon = {pin} onPress ={() => console.log(this.getCache())} status='Partager'>
Partager
</TopNavigationAction>
</View>
<Pdf
source={{ uri: `http://10.1.0.248/${file.path}/${file.filename}`, cache : bool}}
style={styles.pdf}
enablePaging={true}
onLoadComplete={(numberOfPages, filePath) => {
this.state.filePath.push(filePath);
this.setState({ numberOfPages: numberOfPages });
}}
onPageChanged={(page, numberOfPages) => {
this.setState({ page: page });
}}
/>
</Layout>
)}
</ViewPager>
</>
);
}
}
You can use it like this.
await AsyncStorage.getItem('cache'); returns a JSON stringified value which you could parse and use.
async getCache () {
const ta = await AsyncStorage.getItem('cache');
console.log(JSON.parse(ta))
}
Use it likewise
let ta = await AsyncStorage.getItem('cache');
ta = JSON.parse(ta);

How to access device folder using react native file system

I needed to fetch files from a custom folder I created with my rncamera roll app, I used react-native-fs to access the folder but was not able to get the files even though I correctly specified the folder name, but I get a Possible Unhandled Promise Rejection (id:7): Error: Folder does not exist. How can I access this folder?
Even when I removed the folder name RNFS.readDir(RNFS.ExternalStorageDirectoryPath) to check my console.log result I got the error "isFile is not a function".
What is wrong with this code and how do I correct them.
UNSAFE_componentWillMount() {
RNFS.readDir(RNFS.ExternalStorageDirectoryPath+"myApp Videos")
.then((result) => {
console.log('GOT RESULT', result);
return Promise.all([RNFS.stat(result[0].path), result[0].path]);
})
.then((statResult) => {
let videos = []
var allowedExtensions = /(\.avi|\.mp4|\.mov|\.wmv|\.avi)$/i;
statResult.forEach(item => {
if (item.isFile() && !allowedExtensions.exec(item.originalFilepath)) {
videos.push(item)
}
});
console.log(videos)
})
}
setIndex = (index) => {
if (index === this.state.index) {
index = null
}
this.setState({ index })
}
render() {
return (
<View style={styles.container}>
<ScrollView
contentContainerStyle = {styles.scrollview}
{
...this.state.videos && this.state.videos.length > 0 && this.state.videos.map((p, i) => {
const isSelected = i === this.state.index;
const divide = isSelected && this.share === true ? 1 : 3;
return(
<Video
source={{uri: videos}}
style={{opacity: i === this.state.index ? 0.5 : 1, width: width/divide, height: width/divide}}
key={i}
underlayColor='transparent'
onPress={() => this.setIndex(i)}
ref={ref => {
this.player = ref;
}} // Store reference
onError={this.videoError} // Callback when video cannot be loaded
/>
)
})
}
>
</ScrollView>
</View>
);
}

react-native local filesystem storage for images

As a learning exercise, I'm writing a react-native-cli based photo application which should work in a offline mode. What I mean is, application provides a way to either take a picture using camera or select a photo from a built-in gallery and stores them in local filesystem whose directory path is stored in a realm database. Following is my stack,
System: Ubuntu Linux,
react-native-cli: 2.0.1
react-native: 0.61.4,
realm#3.4.2,
react-native-image-picker#1.1.0
With react-native-image-picker, I can either pick a photo or take a photo whose details are stored in the response object from image-picker as,
response.data (image data) and response.uri
ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) {
alert('User cancelled image picker');
} else if (response.error) {
alert('ImagePicker Error: ', response.error);
} else {
const source = { uri: response.uri };
const sourceData = response.data;
this.setState({
imageSourceData: source,
});
}
});
In Main.js I've a simple view,
import React, { Component } from 'react';
function Item({ item }) {
return (
<View style={{flexDirection: 'row'}}>
<Text>{item.picureName}</Text>
</View>
<Image source={uri: ....????} /> <------------- How this would work?
)
}
export default class Main extends Component {
state = {
size: 0,
pictureName: null,
picureLocation: null,
picureDate: new Date(),
imageSourceData: '',
picures: []
}
componentDidMount() {
Realm.open(databaseOptions)
.then(realm => {
const res = realm.objects(PICTURE_SCHEMA);
this.setState({
pictures: res
})
});
}
render() {
return(
<View>
<Image source={uri: 'data:image/jpeg;base64,' + this.state.imageSourceData}
style:{{width: 50, height:50}}/>
<FlatList
data={this.state.pictures}
renderItem={({ item }) => <Item item={item} />}
keyExtractor={item => item.pictureID}
>
</View>
)
}
}
I need to do following, once I get the image from the ImagePicker,
1) store this data in a file on the device and get a file location.
2) Store the location with other meta data in a realm object
saveButton() {
// Store the imageSourceData into a file on a device,
// Get the fileLocation
// update state.picureLocation property
this.addOnePicture()
}
addOnePicture() {
var obj = new Object();
obj = {
PicureID: this.state.size + 1;
PictureName: this.state.pictureName,
PictureDate: this.state.pictureDate,
PicureLocation: this.state.picureLocation
};
Realm.open(databaseOptions)
.then(realm => {
realm.write(() => {
realm.create(PICTURE_SCHEMA, obj);
this.setState({ size: realm.objects(PICTURE_SCHEMA).length });
});
})
}
3) List of realm objects can be read to display the data in a flatlist in "componentDidMount() hook"
It's a snippet of a code but I hope it's clear. I would really appreciate any help/suggestions with possible code block to do following,
1) How do you store the data (imageSourceData) to a local file, basically fill in saveButton() (I was thinking of using react-native-fs package. Is this a good idea?)
2) How do I display this image in a view? Do I need to read the contents as it renders in a FlatList? What does Image syntax looks like (check Item component code).
react-native-fs worked perfectly.

How can I download file from server into a specific folder in my project code workspace in react-native?

I have a react-native project witch I need to update my assets sometimes,
I have an 'app/assets' folder in my project root near the app.js, I installed 'react-native-fetch-blob' to download file and also using it's file system api to write it in my 'assets' folder but I cant save it in my folder I can only use 'RNFetchBlob.fs.dirs.DocumentDir' that I dont know where it is and Also I cant use it in my code,
How can I write my downloaded file exactly into my 'assets' folder?
here is my code :
import RNFetchBlob from 'rn-fetch-blob'
type Props = {};
export default class App extends Component<Props> {
constructor(){
super();
this.state = {
download : 'not yet'
}
}
componentDidMount(){
this._testDownload();
}
_testDownload = () => {
RNFetchBlob.fetch('GET', 'https://www.gstatic.com/webp/gallery3/1.png', {
Authorization : 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzIwMDY4MDEsInVpZCI6Mjk5LCJ1c2VybmFtZSI6Imd1ZXN0XzM5MjQ4NDUiLCJlbWFpbCI6IiIsInJvbGVzIjpbIlVTRVIiXX0.gQ_Gqehx3tcWYI0C5CGmpaTfT33t_TPCKbuIYYOqVBU',
'Content-Type' : 'octet-stream',
// more headers ..
})
.then((res) => {
let status = res.info().status;
console.log('status' , status)
if(status == 200) {
// the conversion is done in native code
let base64Str = res.base64()
RNFetchBlob.fs.writeFile(`${RNFetchBlob.fs.dirs.DocumentDir}/app/assets/1.png`, base64Str, 'base64')
.then(()=>{
console.log('here check')
}).catch(err => console.log('err', err))
} else {
// handle other status codes
}
})
// Something went wrong:
.catch((errorMessage, statusCode) => {
// error handling
})
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{this.state.download}</Text>
</View>
);
}
}
Use this code for download image using RNFetchBlob
more information visit
https://www.npmjs.com/package/rn-fetch-blob?activeTab=dependents
import RNFetchBlob from 'rn-fetch-blob'
type Props = {};
export default class App extends Component<Props> {
constructor(){
super();
this.state = {
download : ''
}
}
componentDidMount(){
this._testDownload();
}
_testDownload = () => {
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: "Storage",
message: "This app would like to store some files on your phone"
}
)
.then(() => {
let dirs =
`/storage/emulated/0/app/assets/`
RNFetchBlob.config({
path: dirs + '/1.png',
fileCache: true
})
.fetch("GET",' https://www.gstatic.com/webp/gallery3/1.png', {})
.then(res => {
console.log("res.data============================", res.data);
})
.catch(err => {
console.log("Error ", err);
});
}
})
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{this.state.download}</Text>
</View>
);
}
}