React Native image upload - reactjs

I am having an issue with uploading an image from my camera roll or to my API. here is the code that I am currently using. I am able to get the image data from both the camera roll and camera. I just am having an issue of posting the data to the server. I don't know where I am getting confused.
import React, { Component } from 'react';
import {
Text,
View,
PixelRatio,
TouchableOpacity,
Image,
Platform,
NativeModules,
DeviceEventEmitter
} from 'react-native';
import { connect } from 'react-redux';
import ImagePicker from 'react-native-image-picker';
import { captureProflieAvitar } from '../../actions';
var RNUploader = NativeModules.RNUploader;
class NewCamera extends Component {
state = {
avatarSource: null,
imgBase64: []
}
componentDidMount() {
// upload progress
DeviceEventEmitter.addListener('RNUploaderProgress', (data) => {
const bytesWritten = data.totalBytesWritten;
const bytesTotal = data.totalBytesExpectedToWrite;
const progress = data.progress;
console.log(bytesWritten, bytesTotal);
console.log( "upload progress: " + progress + "%");
});
}
selectPhotoTapped() {
const options = {
quality: 0.75,
maxWidth: 300,
maxHeight: 300,
storageOptions: {
skipBackup: true
}
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled photo picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
let source;
// You can display the image using either:
source = { uri: 'data:image/jpeg;base64,' + response.data, isStatic: true };
const temp = response.data;
//Or:
if (Platform.OS === 'android') {
source = { uri: response.uri, isStatic: true };
} else {
source = { uri: response.uri.replace('file://', ''), isStatic: true };
}
this.setState({
avatarSource: source,
imgBase64: temp,
});
}
});
}
doUpload() {
const files = {
filepath: `data:image/png;base64,${this.state.imgBase64}`,
};
const opts = {
url: 'https://central.tipflip.co?apior=MYAPIKEY&tfReqID3031&tfUserID=1&tfImage=',
files,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
};
RNUploader.upload(opts, (err, response) => {
if (err) {
console.log(err);
return;
}
const status = response.status;
const responseString = response.data;
const json = JSON.parse(responseString);
console.log('upload complete with status ' + status);
});
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this.selectPhotoTapped.bind(this)}>
<View style={[styles.avatar, styles.avatarContainer, { marginBottom: 20 }]}>
{ this.state.avatarSource === null ? <Text>Select a Photo</Text> :
<Image style={styles.avatar} source={this.state.avatarSource} />
}
</View>
</TouchableOpacity>
<TouchableOpacity
style={{
backgroundColor: 'yellow',
width: 60,
height: 20,
marginTop: 20,
justifyContent: 'center',
alignItems: 'center' }}
onPress={this.doUpload.bind(this)}
>
<Text>Upload</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
backgroundColor: 'yellow',
width: 60,
height: 20,
marginTop: 20,
justifyContent: 'center',
alignItems: 'center'
}} onPress={this.props.cancel}
>
<Text>Cancel</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = {
container: {
justifyContent: 'center',
alignItems: 'center'
},
avatarContainer: {
borderColor: '#9B9B9B',
borderWidth: 1 / PixelRatio.get(),
justifyContent: 'center',
alignItems: 'center'
},
avatar: {
borderRadius: 75,
width: 150,
height: 150
}
};
export default connect(null, { captureProflieAvitar })(NewCamera);

Here is example to upload image using Fetch API
var photo = {
uri: user.profilePicture,
type: 'image/jpeg',
name: 'photo.jpg',
};
var form = new FormData();
form.append("ProfilePicture", photo);
fetch(
Constants.API_USER + 'me/profilePicture',
{
body: form,
method: "PUT",
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': 'Bearer ' + user.token
}
}
).then((response) => response.json())
.catch((error) => {
alert("ERROR " + error)
})
.then((responseData) => {
alert("Succes "+ responseData)
}).done();
Credits
https://stackoverflow.com/a/36649457/5315786

If anyone trying to upload an image to Laravel using React Native try this. my case i'm using react-native-image-crop-picker with Axios
//create object with uri, type, image name
var photo = {
uri: IMAGE_PATH,
type: 'image/jpeg',
name: 'photo.jpg',
};
//use formdata
var formData = new FormData();
//append created photo{} to formdata
formData.append('image', photo);
//use axios to POST
axios({
method: 'POST',
url: api_url + 'customer/upload-avatar',
data: formData,
headers: {
'Authorization': "Bearer " + YOUR_BEARER_TOKEN,
'Accept': 'application/json',
'Content-Type': 'multipart/form-data;'
}}) .then(function (response) { console.log(response)})
.catch(function (error) { console.log(error.response)
});

if you use react-native-image-picker and try to upload your image on laravel restful API, try this.
// create a state for temp photo
const [photo, setPhoto] = React.useState(null);
// create a function to set a temp photo
const handleChoosePhoto = () => {
launchImageLibrary({noData: true}, (response) => {
if (response && !response.didCancel) {
setPhoto(response);
}
});
};
// create a function to post your temp photo through api
const setData = () => {
const formData = new FormData();
if (photo) {
const tempPhoto = {
uri: photo?.assets[0]?.uri,
type: photo?.assets[0]?.type,
name: photo?.assets[0]?.fileName,
};
formData.append('avatar', tempPhoto);
axios({
method: 'POST',
url: api_url + 'api/upload-avatar',
data: formData,
headers: {
'Authorization': "Bearer " + YOUR_BEARER_TOKEN,
'Accept': 'application/json',
'Content-Type': 'multipart/form-data;'
}})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error.response)
});
}
}

Related

React Redux components with REST Endpoints and reusable components

I am working on a React-Redux (with hooks) project, where I have a baseURL with different endpoints. For example
baseURL = "https://jsonplaceholder.typicode.com"
endpoints = "/posts", "/comments", "/albums"
I have 2 questions:
Where to keep the endpoint in the react (comments) component (for example: "/comments")
How to reuse the code for other components like posts and albums because the accessToken code and headers are same for all of them.
const accessToken = localStorage.getItem("accessToken");
Cookies.set("XSRF-TOKEN", Cookies.get("XSRF-TOKEN"));
var bodyParameters = {
page: 1,
pageSize: 50,
};
return fetch(baseURL, {
credentials: "include",
method: "post",
body: JSON.stringify(bodyParameters),
headers: {
Authorization: `JWT ${accessToken}`,
"X-XSRF-TOKEN": Cookies.get("XSRF-TOKEN"),
"cache-control": "no-cache",
pragma: "no-cache",
},
My redux action looks like this
export const readList = () => {
return (dispatch) => {
const accessToken = localStorage.getItem("accessToken");
Cookies.set("XSRF-TOKEN", Cookies.get("XSRF-TOKEN"));
var bodyParameters = {
page: 1,
pageSize: 50,
};
return fetch(baseURL, {
credentials: "include",
method: "post",
body: JSON.stringify(bodyParameters),
headers: {
Authorization: `JWT ${accessToken}`,
"X-XSRF-TOKEN": Cookies.get("XSRF-TOKEN"),
"cache-control": "no-cache",
pragma: "no-cache",
},
})
.then((response) => {
return response.json();
})
.then((data) =>
dispatch(
{
type: READ_LIST,
payload: data,
},
console.log("Actions: ", data)
)
)
.catch((error) => {
console.log(error.response);
throw error;
});
};
};
and the react component looks like this
import "./styles.css";
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { readList } from "./redux/actionCreators";
import { FormattedMessage } from "react-intl";
import { DataGrid } from "#material-ui/data-grid";
export default function App() {
const dispatch = useDispatch();
const historyList = useSelector(
(state) => state.reducers.commentsData.data || []
);
useEffect(() => {
dispatch(readList());
}, [dispatch]);
let rows = historyList.map((obj, index) => {
return (rows = {
id: index,
"User ID": obj.userId,
Title: obj.title,
Body: obj.body
});
});
const columns = [
{
field: "User ID",
flex: 1,
renderHeader: () => <FormattedMessage id={"userId"} />
},
{
field: "Title",
flex: 1,
value: "dropdown",
renderHeader: () => <FormattedMessage id={"title"} />
},
{
field: "Body",
flex: 1,
type: "date",
renderHeader: () => <FormattedMessage id={"body"} />
}
];
return (
<div className={"uhes-pageWrapper"}>
<h1 className="uhes-pageHeader">
<FormattedMessage id="History" />
</h1>
<div style={{ height: "90%", width: "100%" }}>
<DataGrid
pageSize={50}
rowsPerPageOptions={[50, 100, 150]}
rows={rows}
columns={columns}
/>
</div>
</div>
);
}
Thank you!
The ideas to reuse api configs, includes baseURL, accesstoken,... somethings like this
You will have a service called apiService: where you manage your fetch configs like headers, and you can also add your token in there. apiService will return REST functions: POST/PUT/GET/DELETE/PATCH with available header configurations
Example:
const customFetch = (path, options) => {
const accessToken = localStorage.getItem("accessToken");
Cookies.set("XSRF-TOKEN", Cookies.get("XSRF-TOKEN"));
var bodyParameters = {
page: 1,
pageSize: 50
};
return fetch(`${baseURL}/${path}`, {
credentials: "include",
headers: {
Authorization: `JWT ${accessToken}`,
"X-XSRF-TOKEN": Cookies.get("XSRF-TOKEN"),
"cache-control": "no-cache",
pragma: "no-cache"
},
...options
});
};
const post = (path, bodyParameters) =>
customFetch(path, {
method: "POST",
body: JSON.stringify(bodyParameters)
});
const get = (path, queries) =>
customFetch(queries ? `${path}/${qs.stringify(queries)}` : path, {
method: "GET"
});
const put = (path, bodyParameters) =>
customFetch(path, {
method: "PUT"
body: JSON.stringify(bodyParameters)
});
const delete = (path, id) =>
customFetch(`${path}/${id}`, {
method: "DELETE"
});
After that you can custom your readList with dynamic endpoint like this
const readList = (resource) => apiService.get(resource)
readList('/posts');
readList('/comments');
readList('/albums');

Pick images in react native and upload it

I want to upload an array of images using react-native-image-crop-picker but I can't fix it.
What I've tried:
Fetch (javascript) and also RN-fetch-blob but no luck
At first the catch error was network error
and now the problem is that I'm sending an empty array to the server
here is my code:
export default class Upload extends Component {
constructor() {
super();
this.state = {
token: '',
photos: [],
};
}
_TakePhoto() {
ImagePicker.openPicker({
multiple: true,
}).then((images) => {
images.map((item, index) => {
ImageResizer.createResizedImage(item.path, 1200, 1200, 'JPEG', 100)
.then((response) => {
// console.warn('Resized img is: ', response);
this.state.photos.push(response);
console.warn('Resized img state is: ', this.state.photos);
this._submit_pictures();
})
.catch((err) => {});
});
});
}
_submit_pictures() {
let formData = new FormData();
for (let i = 0; i < this.state.photos.length; i++) {
let file = {
uri: this.state.photos[0].path,
// uri: this.state.photos[0].path.replace('file:///', ''),
// uri: this.state.photos[0].uri,
type: this.state.photos[0].mime,
name: this.state.photos[0].name,
};
formData.append('pics[]', file);
}
// uri: this.state.photos[0].uri.replace("file:///", "file://"),
formData.append('postId', postId);
formData.append('token', token);
console.log('formData value: ', formData);
axios({
url: 'https://rahnama.com/webservice/submitPictures',
method: 'POST',
headers: {
// "Accept": "application/json",
'Content-Type': 'multipart/form-data',
},
// formData
body: formData,
})
.then((response) => {
console.warn('upload res: ', response);
})
.catch((error) => console.warn('upload err: ', error.response.request._response));
}
render() {
return <Text onPress={() => this._TakePhoto()}> Pick </Text>;
}
}
Solved it by sending the image data in base64.
1- Pick the image
2- convert it to base64
3- pass the base64 string as the payload

The localhost api can not be fetched from the expo

The localhost api can not be fetched from the expo.
const search = async(type) => {
let response = await fetch(http://localhost:3000/api/${type}, {
accept: 'application/json'
});
let result = await response.json();
return result;
}
const create = async(type, data) => {
let response = await fetch(http://localhost:3000/api/${type}, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: 'post',
body: JSON.stringify(data)
});
let result = await response.json();
return result;
}
const Client = {search, create};
export default Client;
Client.js
const search = async(type) => {
let response = await fetch(`http://localhost:3000/api/${type}`, {
accept: 'application/json'
});
let result = await response.json();
return result; }
const create = async(type, data) => {
let response = await fetch(`http://localhost:3000/api/${type}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: 'post',
body: JSON.stringify(data)
});
let result = await response.json();
return result;
}
const Client = {search, create};
export default Client;
App.js
import React, { Component } from 'react';
import {
Text,
View,
TextInput,
Button,
StyleSheet
} from "react-native";
import Client from './Client.js';
class App extends Component {
constructor() {
super()
this.state = {
users: [] // user에 대한 정보를 담기 위한 state
}
this.handleUserInputChange = this.handleUserInputChange.bind(this)
}
componentWillMount = () => {
this.getUser()
}
handleUserInputChange = event => {
const {target: {name, value}} = event
this.setState({
[name]: value
});
}
getUser = async() => {
Client.search('User') // Client.js에서
.then(data => {
this.setState({
users: data
})
})
}
submitUser = () => {
const data = {
"$class": "org.acme.model.User",
"phonenumber": this.state.phonenumber,
"email": this.state.email,
"firstName": this.state.firstName,
"lastName": this.state.lastName,
}
Client.create('User', data)
.then(() => {
this.getUser()
})
}
render() {
return(
<View className="App">
<Text>Add User</Text>
<Text>phonenumber:</Text>
<TextInput
onChange={this.handleUserInputChange}
type="text"
name="phonenumber" />
<Text>email:</Text>
<TextInput
onChange={this.handleUserInputChange}
type="text"
name="email" />
<Text>firstName:</Text>
<TextInput
onChange={this.handleUserInputChange}
type="text"
name="firstName" />
<Text>lastName:</Text>
<TextInput
onChange={this.handleUserInputChange}
type="text"
name="lastName" />
<Button title="New User" onPress={()=> this.submitUser}/>
<View style={styles.container}>
<Text style={styles.userlist}>
User List
</Text>
{this.state.users.map((r, i) => (
<View style={styles.userstate}
key={i}>
<Text>phonenumber: {r.phonenumber}</Text>
<Text>email: {r.email}</Text>
<Text>firstName: {r.firstName}</Text>
<Text>lastName: {r.lastName}</Text>
</View>
))}
</View>
</View>
)
}
}
const styles=StyleSheet.create({
container: {
flex:1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
userlist:{
fontSize: 20,
textAlign: 'center',
margin: 10,
},
userstate:{
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
export default App;
The error is logical, because "localhost" is the name that designates a logical interface of the local computer.
So when you ask your application to make a request to "http://localhost:3000/api", it sends the request to the phone so it will never reach your computer.
But if your local network allows it, you can put directly the IP address of your computer.
You have to expose your APIs. One way you can do this is by using ngrok.
Try the below:
https://ngrok.com/ and follow the steps for installation after signing up
After unzipping open terminal and ./ngrok http <port_number>
If it is working, you should see a Forwarding: <forwarding_address>
Copy this forwarding address as your base url in the app
Just to test, try hitting this forwarding address in your browser, ex. http://1a6b3022.ngrok.io/api/testing you should get a response
Hopefully this is helpful!

Access object in JSON array with this.state in React Native

I am having trouble displaying an object from an array. I want to display id from here:
[
{
"id":"1",
"imagename":"dog"
},
{
"id":"2",
"imagename":"cat"
},
{
"id":"3",
"imagename":"mouse"
},
{
"id":"4",
"imagename":"deer"
},
{
"id":"5",
"imagename":"shark"
},
{
"id":"6",
"imagename":"ant"
}
]
Here is my attempt:
fetch(`http://www.example.com/React/data.php` , {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
id: responseJson[0].id, <-- Attempt to try to get the id from responsejson.
},function() {
// In this block you can do something with new state.
});
})
.catch((error) => {
console.error(error);
});
With this I got undefined is not a function. I am not getting what I am doing wrong or how to access this object.
<FlatList
data={ this.state.dataSource}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => <View>
<Card>
<View>
<Text style={{marginTop: 30}}> {this.state.responseJson.id}</Text>
</View>
</Card>
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
Try the async/await method, you are getting an error because the data is not load and the render function is trying to load the data.
async componentDidMount() {
await fetch(`http://www.example.com/React/data.php`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json()).then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
id: responseJson[0].id
});
}).catch((error) => {
console.error(error);
});
}
Or another approach is to add a loading preloader or spinner like this.
First import the package.
import { ActivityIndicator } from 'react-native';
Second change the render method
render() {
if (isLoading) {
return ( <
View style = {
[styles.container, styles.horizontal]
} >
<
ActivityIndicator size = "large"
color = "#0000ff" / >
<
/View>
);
}
return (
// Your render stuffs
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
horizontal: {
flexDirection: 'row',
justifyContent: 'space-around',
padding: 10
}
})
If any issue please let me know

Connect two modal picker in react native

I use react native modal picker to drop down the data link here
I used two modal picker, that depend on each other. first one is select service. second one is select city. I want to display cities that have particular services. code is here
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Alert,
TouchableHighlight,
Image,
TextInput,
} from 'react-native';
var fullservice=[];
var citylist=[];
import ModalPicker from 'react-native-modal-picker'
class jsonSugei extends Component {
constructor() {
super();
this.state = {
textInputValue: '',
dropdownservices:[],
city:'',
dropdowncities:[],
service:'',
}
}
componentDidMount() {
this.fetchData1();
this.fetchData2();
}
fetchData1(){
fetch("URL",
{method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify( {"cacheRequest":["ALL_COMPANY","ALL_SERVICE","HOT_COMPANY","BANNER","PARTNER","CITY","CALANDAR","COMMENTS "]}),
})
.then((response) => response.json())
.then((responseData) => {
this.setState({
dropdownservices: responseData.services,
});
})
.catch((error) => { console.warn(error); })
.done();
}
fetchData2(){
this.state = {
service:'',
}
fetch("URL",
{method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify( {
"companyId":"",
"service":this.state.service,
"key":""
}),
})
.then((response) => response.json())
.then((responseData) => {
this.setState({
dropdowncities: responseData.cities,
});
})
.catch((error) => { console.warn(error); })
.done();
}
render() {
citylist= this.state.dropdowncities.map(function(item) {
return {
key:item.id,
label: item.name,
};
});
fullservice =this.state.dropdownservices.map(function(item) {
return {
key:item.id,
label: item.name,
};
});
return (
<View style={{flex:1, justifyContent:'space-around', padding:50, backgroundColor: '#ffffff'}}>
<ModalPicker1
data={fullservice}
initValue="Select Services!"
onChange={(option)=>{this.setState({service:option.label})}}
/>
<ModalPicker
style={{marginTop:10}}
data={citylist}
initValue="City"
onChange={(option)=>{ this.setState({city:option.label})}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ffffff',
},
button: {
borderRadius: 4,
padding: 10,
marginLeft: 10,
marginRight: 10,
backgroundColor: "#B8C",
},
});
AppRegistry.registerComponent('jsonSugei', () => jsonSugei);
but not change cities according to the services??? I need help............
The onChange event handler for services ModalPicker should set the state for the cities ModalPicker. Also, the initial fetch for the cities ModalPicker should only fetch cities corresponding to the default service.
Add another function to first modal picker, and set the data entity as a get state variable,
<ModalPicker1 data={fullservice} initValue="Select Services!" onChange={(option)=>{this.setState({service:option.label}),this.secondFunction()}} />
Then set the state.cities variable in the second function and use it as the data entity in second modal picker,
secondFunction(){
this.setState({cities:array});
}
<ModalPicker2 data={this.state.cities} initValue="City" onChange={(option)=>{this.setState({city:option.label})}} />

Resources