I'm trying to upload images that I've base64 encoded but it doesn't seem to save the state to the app so I can upload the images to my server. The state only seems to save within the function and not to the entire component. Any suggestions as to what I'm doing wrong?
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.state = {
selected: image
};
console.log(this.state)
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity style={ styles.button } onPress={ this._addImage.bind( this ) }>
<Text>Add Image</Text>
</TouchableOpacity>
<TouchableOpacity style={ styles.button } onPress={this._uploadImage} >
<Text>Upload Image</Text>
</TouchableOpacity>
</View>
<ScrollView style={styles.container}>
<View style={styles.imageGrid}>
{ this.state.images.map((image) => {
return (
<TouchableHighlight onPress={this._selectImage.bind(null, image.uri)}>
<Image key={ _generateUUID() } style={styles.image} source={{ uri: image.uri }} />
</TouchableHighlight>
);
})
}
</View>
</ScrollView>
</View>
);
}
};
First, this-bind your _selectImage-method in constructor. Then use "setState" instead of this.state = {...}
You need only once to create the state object, best in constructor. Use then setState instead for further modifications.
constructor(props) {
super(props);
this.state = {selected: null};
this._selectImage = this._selectImage.bind(this);
}
_selectImage(uri) {
NativeModules.ReadImageData.readImage(uri, (image) => {
this.setState({
selected: image
});
console.log(this.state)
});
}
Related
I am trying to detect touch on a view in React Native. I followed this link and incorporated the Touchable around my styled view like so:
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.card}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
I am using a functional component, so after export default function App() { I have:
function cardPressed()
{
console.log('pressed');
}
No errors, but I get nothing. What is wrong w this implementation?
Check your import. You should import TouchableWithoutFeedback from react-native and not from react-native-gesture-handler
Check out this code.
import React, { useState } from "react";
import { StyleSheet, TouchableWithoutFeedback, Text, View } from "react-native";
const App = () => {
const [count, setCount] = useState(0);
const cardPressed = () => {
console.log('pressed');
setCount(count + 1);
};
return (
<View style={styles.container}>
<View style={styles.countContainer}>
<Text style={styles.countText}>Count: {count}</Text>
</View>
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.button}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
paddingHorizontal: 10
},
button: {
alignItems: "center",
backgroundColor: "#DDDDDD",
padding: 10
},
countContainer: {
alignItems: "center",
padding: 10
},
countText: {
color: "#FF00FF"
},
card_Head: {
fontWeight: 'bold',
fontSize: 24
},
card_Body: {
fontStyle: 'italic'
}
});
export default App;
export default class HistoryScreen extends BaseScreen {
constructor(props){
super(props);
this.state = {
mainListData:[],
listData:[],
searchText:'',
};
}
listRowPressed(item) {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex:1, backgroundColor: '#FFF'}}>
<FlatList
data={this.state.listData}
renderItem={({item}) => <ListComp data={item} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = item => (
<TouchableOpacity onPress={() => this.listRowPressed(item)
}>
<View style={styles.row}>
</View>
</TouchableOpacity>
);
I am displaying data in FlatList, however clicking on item gives me this4. listRowPressed is undefined, I tried binding the function too but didn't work. What is wrong in the code?
You have to pass listRowPressed in your ListComp component. Your whole code should be like this :
export default class HistoryScreen extends BaseScreen {
constructor(props) {
super(props);
this.state = {
mainListData: [],
listData: [],
searchText: '',
};
}
listRowPressed = (item) => {
this.props.navigation.navigate('Details', {
checkin: item.data
});
}
render() {
return (
<View style={styles.container}>
<View style={{ flex: 1, backgroundColor: '#FFF' }}>
<FlatList
data={this.state.listData}
renderItem={({ item }) => <ListComp data={item} listRowPressed={this.listRowPressed} />}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}
const ListComp = (props) => (
<TouchableOpacity
onPress={() => props.listRowPressed(props.item)}
>
<View style={styles.row}>
{/* Do whatever with props.item here */}
</View>
</TouchableOpacity>
);
Also note that I have converted your method listRowPressed simple function to arrow function.
Try this
<FlatList
data={this.state.listData}
renderItem={this.listComp}
keyExtractor={(item, index) => index.toString()}
/>
listComp = ({item}) => (
return(
<TouchableOpacity onPress={() => this.listRowPressed(item)} >
<View style={styles.row}>
</View>
</TouchableOpacity>
);
);
I am using the react-native-camera plugin in my app. I am trying to take an image and then immediately upload it to an AWS S3 bucket via AWS Amplify.
My Code looks like this:
export default class Camera extends Component {
render() {
return (
<View style={styles.container}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={styles.preview}
flashMode={RNCamera.Constants.FlashMode.auto}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your phone\'s camera'}
/>
<TouchableOpacity
onPress={this.takePicture.bind(this)}
style={styles.capture}
>
<Text style={{fontSize: 15}}> SNAP </Text>
</TouchableOpacity>
</View>
);
}
takePicture = async function () {
if (this.camera) {
const options = {base64: true};
const data = await this.camera.takePictureAsync(options);
console.log(data.uri);
uploadPictureToS3(data.uri, "image.jpg");
}
};
}
function readFile(fileUri) {
return RNFetchBlob.fs.readFile(fileUri, 'base64').then(data => new Buffer(data, 'base64'));
}
function uploadPictureToS3(uri, key) {
readFile(uri).then(buffer => {
Storage.put(key, buffer, {
contentType: "image/jpeg"
})
})
.then(r => {
console.log(r);
})
.catch(e => {
console.error(e);
});
}
When trying to access the file using the readFile method I get the following error: Error: file not exists.
What is happening here? Why am I not able to read the image from the cache folder directly after it was taken?
Your code looks alright although there are some "weird" stuff.
You pass the option base64 to the takePictureAsync. This makes the camera return the base64 of picture taken automatically, but you do not use it for anything. You can do uploadPictureToS3(data.base64, "image.jpg"); And skip the readFile method.
Another thing is, don't know why it is like this, to get the image base64 from the uri we usually do:
const filepath = data.uri.split('//')[1];
const imageUriBase64 = await RNFS.readFile(filepath, 'base64');
So try the const filepath = data.uri.split('//')[1]; trick instead of passing data.uri directly.
i am using the RNCamera plugin in this app,this code show image tack by camera in app
import React, { Component } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, Image } from 'react-native';
import { RNCamera } from 'react-native-camera';
export default class CameraPage extends Component {
constructor(props) {
super(props);
this.state = {
img : '',
}
}
takePicture = async function(camera) {
const options = { quality: 0.5, base64: true };
const data = await camera.takePictureAsync(options);
this.setState({
img: data.uri
})
};
render() {
const{img}= this.state;
return (
<View style={styles.container}>
<RNCamera
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.off}
permissionDialogTitle={'Permission to use camera'}
permissionDialogMessage={'We need your permission to use your camera phone'}
>
{({ camera}) => {
return (
<View style={{ flex: 0, flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity onPress={() => this.takePicture(camera)} style={styles.capture}>
<Text style={{ fontSize: 14 }}> SNAP </Text>
</TouchableOpacity>
</View>
);
}}
</RNCamera>
<View style={{flex:1,justifyContent: 'center', alignItems: 'center'}}>
<Image source={{uri:img}} style={{ width: 200, height: 200}}/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black',
},
preview: {
flex: 2,
justifyContent: 'flex-end',
alignItems: 'center',
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
padding: 15,
paddingHorizontal: `**enter code here**`20,
alignSelf: 'center',
margin: 20,
},
});
I want to Push to a new Component by the function push() in NavigatorIOS. It's like following:
renderRow(rowData, sectionID, rowID) {
var imgSource = IMAGE_URLS[rowID];
return (
<TouchableHighlight onPress = {() => {
this.props.navigator.push({
title: 'test',
component: example,
});
}}>
<View>
<View style={styles.row}>
<Image
source={imgSource}
style={styles.thum}
/>
<Text style={styles.text}>
{rowData}
</Text>
</View>
</View>
</TouchableHighlight>
);
}
But it will get a error when I click the TouchableHighlight.
I refered these two questions(1 and 2) before this. And the complete code is in this link
this is not binded to the class inside of renderRow().
You have to bind this either in the constructor:
this.renderRow = this.renderRow.bind(this);
or inside the render method:
render() {
var navStatusBarConfig = {
style: 'light-content',
}
return (
<View style={{ flex: 1, backgroundColor: '#F5FCFF'}}>
<View styles={styles.nav}></View>
<ListView
automaticallyAdjustContentInsets={false}
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
pageSize={4}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
As to why, here is the reason :
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
And a more complete blog about how to bind this [there are many, blogs and ways to bind this]) :
http://blog.andrewray.me/react-es6-autobinding-and-createclass/
So I have an Initial Screen below which allows you to click on a button and present a modal screen:
import SettingsScreen from './SettingsScreen';
...
export default class InitialScreen extends Component {
constructor(props) {
super(props);
this.state = {modalVisible: false};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View>
<NavigationBar
title={{ title: 'Initial Screen', tintColor: 'white', }}
leftButton={
<TouchableOpacity onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Image style={styles.leftButton} source={require('./../img/settings.png')} />
</TouchableOpacity>
}
rightButton={{ title: 'Forward', tintColor: 'white' }}
style={{ backgroundColor: '#2196F3', }}
statusBar={{ tintColor: '#1976D2', style: 'light-content' }}
/>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<SettingsScreen />
</Modal>
</View>
);
}
}
It works, but now in my Modal screen I have a button which allows you to dismiss the modal:
import ...
export default class ModalScreen extends Component {
render() {
return (
<View>
<TouchableOpacity onPress={() => {
this.props.setModalVisible(!this.state.modalVisible)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>
</View>
);
}
}
But it's giving me an error saying this.props.setModalVisible(!this.state.modalVisible) is not a function.
How would I dismiss the modal within the ModalScreen?
Thank you.
you should pass the setModalVisible() function to the modal component
Initial Component:
<ModalComponent closeModal={this.setModalVisible} />
and on ModalComponent call it like this:
<TouchableOpacity onPress={() => {
this.props.closeModal(false)
}}>
<Image source={require('./../img/close.png')} />
</TouchableOpacity>
For custom functions in react native use ES6 style:
setModalVisible = (visible) => {
this.setState({modalVisible: visible});
}
And the code should be: this.setModalVisible(!this.state.modalVisible)