Decode QR Code Image from Camera Roll React Native - javascript

I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.
I'm currently using react-native-camera-roll-picker: https://github.com/jeanpan/react-native-camera-roll-picker
and react-native-qrcode-local-image: https://github.com/remobile/react-native-qrcode-local-image
The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.
I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well: https://github.com/wkh237/react-native-fetch-blob
This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):
_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
tmpBlob = b;
RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
});
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
})*/
}
I'm at a total loss at the moment so any methods or insight would be much appreciated.

you can use react-native-qrcode-scanner to scan QR from images or directly through the camera.
INSTALLATION:
install dependency by using this command:
yarn add react-native-camera react-native-qr-scanner
link those libraries by using:
react-native link react-native-camera && react-native-qr-scanner
you need to add the permission to your AndroidManifest.xml of your project. This should be found in your android/app/src/main/AndroidManifest.xml Add the following:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE"/>
With iOS 10 and higher, you need to add the "Privacy - Camera Usage Description" key to the info.plist of your project. This should be found in your_project/ios/your_project/Info.plist. Add the following code:
<key>NSCameraUsageDescription</key>
<string/>
<key>NSPhotoLibraryUsageDescription</key>
<string/>
<key>NSMicrophoneUsageDescription</key>
<string/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string/>
Usage:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {QRreader} from 'react-native-qr-scanner';
import ImagePicker from 'react-native-image-picker';
export default class Scanner extends Component {
constructor(props) {
super(props);
this.state = {
reader: {
message: null,
data: null
}
};
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={()=>{
this.openPhoto();
}}>
<Text style={{marginTop: 20}}>打开相册识别二维码</Text>
</TouchableOpacity>
<View>
{!this.state.reader? <Text>{!this.state.reader.message?'':`${this.state.reader.message}`}</Text>: <Text>{!this.state.reader.message?'':`${this.state.reader.message}:${this.state.reader.data}`}</Text>}
</View>
</View>
);
}
openPhoto(){
console.log('ImagePicker');
ImagePicker.launchImageLibrary({}, (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 if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
if(response.uri){
var path = response.path;
if(!path){
path = response.uri;
}
QRreader(path).then((data)=>{
this.setState({reader: {
message: '识别成功',
data: data
}});
// 十秒后自动清空
setTimeout(() => {
this.setState({reader: {
message: null,
data: null
}})
}, 10000);
}).catch((err)=>{
this.setState({reader: {
message: '识别失败',
data: null
}});
});
}
}
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff'
}
});
you can read more about this library here: https://www.npmjs.com/package/react-native-qr-scanner

You can use react-native-camera to solve this issue easily.
Here's the simple code snippet for that.
handleCodeDetected = (data) => {
// do whatever you want to do with data
}
...
...
<RNCamera
type={RNCamera.Constants.Type.back}
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
onBarCodeRead={this.handleCodeDetected}
style={styles.preview}
/>

This answer solved it for me.
Created native method to covert uri in path, here is my code:
#ReactMethod
public void getRealPathFromURI(String contentUriString, Promise promise) {
Uri contentUri = Uri.parse(contentUriString);
Cursor cursor = null;
try {
String wholeID = DocumentsContract.getDocumentId(contentUri);
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
String sel = MediaStore.Images.Media._ID + "=?";
cursor = reactContext.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
int columnIndex = cursor.getColumnIndex(column[0]);
String filePath = "";
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
promise.resolve(filePath);
} catch (Throwable e) {
promise.reject(e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
And js:
DocumentPicker.pick({ type }).then((document: DocumentPickerResponse) => {
MyNativeModule.getRealPathFromURI(document.uri).then((path) => {
QRCodeLocalImage.decode(path, (err, res) => {
callback(err, { qrData: res });
});
});
});

You can just use react-native-rn-zxing:
npm i react-native-rn-zxing
then link it :
react-native link react-native-rn-zxing
Usage :
import RnZxing from 'react-native-rn-zxing';
...
// Pass the callback as a parameter
RnZxing.showQrReader(this.onBarcodeScanned);
...
// Define the callback function to handle data after scan
onBarcodeScanned = (data) => {
this.setState({data: data});
};

You can use rn-qr-generator
It can detect QR code in image
RNQRGenerator.detect({
uri: PATH_TO_IMAGE, // local path of the image. Can be skipped if base64 is passed.
base64: imageBase64String, // If uri is passed this option will be skipped.
})
.then(response => {
const { values } = response; // Array of detected QR code values. Empty if nothing found.
})

Related

SvelteKit Maintenance Mode

Is there a good way to do display a maintenance page when visiting any route of my SvelteKit website?
My app is hosted on Vercel, for those who want to know.
What I've tried so far:
Set an environment variable called MAINTENANCE_MODE with a value 1 in Vercel.
For development purposes I've set this in my .env file to VITE_MAINTENANCE_MODE and called with import.meta.env.VITE_MAINTENANCE_MODE.
Then inside +layout.server.js I have the following code to redirect to /maintenance route
import { redirect } from "#sveltejs/kit";
export async function load({ url }) {
const { pathname } = url;
// Replace import.meta.env.VITE_MAINTENANCE_MODE with process.env.MAINTENANCE_MODE in Production
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
if (pathname == "/maintenance") return;
throw redirect(307, "/maintenance");
  } else {
if (pathname == "/maintenance") {
throw redirect(307, "/");
    };
  };
};
What I've also tried is just throwing an error in +layout.server.js with the following:
import { error } from "#sveltejs/kit";
export async function load() {
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
throw error(503, "Scheduled for maintenance");
  };
};
However this just uses SvelteKit's static fallback error page and not +error.svelte. I've tried creating src/error.html in the hope to create a custom error page for +layout.svelte but couldn't get it to work.
I would like to use a custom page to display "Down for maintenance", but I don't want to create an endpoint for every route in my app to check if the MAINTENANCE_MODE is set to 1.
Any help is appreciated
You could use a handle server hook, e.g. src/hooks.server.ts:
import { env } from '$env/dynamic/private';
import type { Handle } from '#sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
if (env.MAINTENANCE_MODE == '1' && event.routeId != '/maintenance')
return new Response(undefined, { status: 302, headers: { location: '/maintenance' } });
// <other logic>
// Default response
return await resolve(event);
}
And on the maintenance page you can prevent all further navigation:
import { beforeNavigate } from '$app/navigation';
beforeNavigate(async ({ cancel }) => {
cancel();
});
(Possibly add some periodic checks via fetch calls to navigate elsewhere once the site is back online.)
You can also use +layout.ts to hook up for the maintenance mode. You can even make this conditional for some parts of the site (have frontpage still up and running).
Here is the trick we use:
import type { LayoutLoad } from './$types';
import { chainsUnderMaintenance } from '$lib/config';
import { error } from '#sveltejs/kit';
export const load: LayoutLoad = ({ params }) => {
// Check chain maintenance status; if under maintenance, trigger error (see +error.svelte)
const chainName = chainsUnderMaintenance[<string>params.chain];
if (chainName) {
throw error(503, `Chain under maintenance: ${chainName}`);
}
};

Imagepicker React Native crashes on iOS but works fine on Android

I am currently using imagepicker on react native. When I use android to pick image it works fine. However when I use iOS it crashes when I choose a photo.
This is the error it shows in xcode debugger:
2020-04-03 11:54:27.802434+0800 app[7218:1993193] -[NSURLResponse allHeaderFields]: unrecognized selector sent to instance 0x28281aba0
2020-04-03 11:54:27.802766+0800 app[7218:1993193] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLResponse allHeaderFields]: unrecognized selector sent to instance 0x28281aba0'
* First throw call stack:
(0x19d01c164 0x19cd30c1c 0x19cf1a7e0 0x19d02085c 0x19d022b60 0x102b27bc8 0x102b27a90 0x102b01ce0 0x1059f5d10 0x1059f718c 0x1059fe968 0x1059ff580 0x105a0b0f0 0x19cd23714 0x19cd299c8)
libc++abi.dylib: terminating with uncaught exception of type NSException
and this is my code:
chooseImage = async (id) => {
//await this.askPermissionsAsync();
let options = {
title: 'Select Image',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response.error);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
const source = { uri: response.uri };
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
// alert(JSON.stringify(response));
let file_data = [...this.state.fileData];
file_data[id] = response.data;
let file_uri = [...this.state.fileUri];
file_uri[id] = response.uri;
this.setState({filePath:response, fileData: file_data, fileUri: file_uri});
}
});
}
I have also added the permissions in info.plist:
<key>NSCameraUsageDescription</key>
<string></string>
<key>NSPhotoLibraryUsageDescription</key>
<string></string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string></string>
<key>NSDocumentsFolderUsageDescription</key>
<string></string>
but the problem still persist in ios.
The issue was
'data:image/jpeg;base64,' + this.state.fileData[id]
while rendering it on Image tag.
This issue is indicated here:
YellowBox Crash
Image Crash with data:image/png;base64
The solution I did was to add "noData: true" on option and access directly the URI file location in the image tag.
Hope this helps
react-native link did not link the library, so the mage picker lib did not build with the app. Thats why I as getting null pointer exception because there was no lib.
Or else manually add the library.
<key>NSCameraUsageDescription</key>
<string>Access to take a photo by camera</string>
<key>NSAppleMusicUsageDescription</key>
<string>Access to pick a photo</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to pick a photo</string>

Getting "Illegal callback invocation from native module. This callback type only permits a single invocation from native code"

I am using react-native-image picker and react-native-image-crop picker libraries in two class.
One is launching the library image (react-native-image picker) and other one package opens the cropping window(react-native-image-crop-picker).
Here the launching library is in one screen and cropper is opening while navigating from the library on another screen.
My issue is after click on the choose-in cropping window it again reset the cropping window and need to crop again and illegal invocation error occurs after this.
Refer the code sniipet
// Opens the library image in Library.js screen
import ImagePicker from 'react-native-image-picker';
ImagePicker.launchImageLibrary(options, (response) => {
if (response.didCancel) {
console.warn('User cancelled photo picker');
}
else if (response.error) {
console.warn('ImagePicker Error: ', response.error);
}
else {
this.props.navigation.navigate('CropWindow', { screenName: 'CropImage',uri: response.uri});
}
The below is for the cropping window in CropWindow.js
import ImagePicker from 'react-native-image-crop-picker';
ImagePicker.openCropper({
path: response,
width: deviceWidth,
height: deviceWidth*5/4
}).then(image => {
this.props.navigation.navigate('ShowAllCroppedImage', {uri: response.uri, croppedImage: this.croppedImage.bind(this)});
})
.catch((err) => {
console.log("openCropper error = " + err)
});
its issue with permissions for android
import { PermissionsAndroid } from 'react-native';
async requestCameraPermission() {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
'title': 'Cool Photo App Camera Permission',
'message': 'Cool Photo App needs access to your camera ' +
'so you can take awesome pictures.'
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log("You can use the camera")
} else {
console.log("Camera permission denied")
}
} catch (err) {
console.warn(err)
}
}
You do not need to use two modules at the same time. You can get what you want with a simple execution.
Before that, get the rights to the camera and storage space.
You can use yarn add react-native-permissions #react-native-community/async-storage
and react-native link react-native-permissions
Example
import Permissions from 'react-native-permissions';
...
_requestPermission = () => {
Permissions.request('photo').then(response => {
// Returns once the user has chosen to 'allow' or to 'not allow' access
// Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
this.setState({photoPermission: response});
});
Permissions.request('camera').then(response => {
// Returns once the user has chosen to 'allow' or to 'not allow' access
// Response is one of: 'authorized', 'denied', 'restricted', or 'undetermined'
this.setState({photoPermission: response});
});
};
If you want to cut an one image
import ImagePicker from 'react-native-image-crop-picker';
...
ImagePicker.openPicker({
width: deviceWidth,
height: deviceWidth*5/4
cropping: true
}).then(image => {
console.log(image);
});
If you want to cut multiple images:
import ImagePicker from 'react-native-image-crop-picker';
...
ImagePicker.openPicker({
multiple: true,
width: deviceWidth,
height: deviceWidth*5/4
cropping: true
}).then(images => {
console.log(images);
});

Firebase Storage | Angular 2 - Proper way to display image after upload

When creating an event, I also upload an image to Firebase Storage.
Then I create an array this.eventz to display the events on the home page. For each event I want to retrieve the image as well, but I get a Firebse error:
FirebaseStorageError {code_: "storage/object-not-found", message_: "Firebase Storage: Object 'events/-KxCuUuss1I2uFolk99m/-KxCuUuss1I2uFolk99m_main.png' does not exist.", serverResponse_: "{↵ "error": {↵ "code": 404,↵ "message": "Not Found. Could not get object"↵ }↵}", name_: "FirebaseError"}
I understand that the image isn't uploaded yet when I want to include it in the array but I don't know how to fix my problem. The code works fine. It displays all the events, adds images to each one ... it's just that error when creating a new event.
getEventImage(event) {
if (event) {
const mainPhotoRef = firebase.storage().ref('events');
console.log(mainPhotoRef);
mainPhotoRef.child(`/${event.key}/${event.key}_main.png`).getDownloadURL()
.then(url => this.makeEvents(url, event))
}
}
makeEvents(url, event) {
console.log(url);
if (url) {
try {
event.img = url;
let index = _.findIndex(this.eventz, ['key', event.key]);
if (index >= 0) {
this.eventz.splice(index, 1);
}
this.eventz.push(event);
} catch (err) {
console.log(err);
}
}
}
I fixed my problem by saving the url to the event object when creating it. I would like to know if I am uploading correctly.
private uploadPhoto(itemKey): void {
this.myPhotosRef.child(itemKey).child(`${itemKey}_main.png`)
.putString(this.myPhoto, 'base64', { contentType: 'image/png' })
.then((savedPicture) => this.updateEventImage(savedPicture.downloadURL, itemKey));
}
updateEventImage(url, itemKey) {
console.log(url);
const newEvent = this.db.object(`events/${itemKey}`)
newEvent.update({ eventImage: url });
}

How to add a loading indicator on every Relay.js network request

I'm currently building a Relay/React web app. It's been amazingly simple with one exception. I've not been able to figure out how I can get a global notification when any of my components are making network requests. I'm hopping to add a spinner to the top of my app when ever there's network activity, because some of my mutations take a long time to load.
This was my attempt at solving this problem, but it only works on new route page loads.
function renderer(info)
{
let {props, error, element} = info;
if (error) {
return (<ServerError errors={error}/>);
} else {
if (props) {
return React.cloneElement(element, props);
} else {
return (<Loading />);
}
}
}
ReactDOM.render(
<Router
history={browserHistory}
render={applyRouterMiddleware(useRelay)}
environment={Relay.Store}
>
<Route
path="/"
queries={ViewerQuery}
component={App}
>
<IndexRoute
queries={ViewerQuery}
component={Libraries}
render={renderer}
/>
<Route path="*" component={Error}/>
</Route>
</Router>
Ideally I could get some callback that I can pass to my App component, which renders all my pages headers and footers. Any help with this would be greatly appreciated. I've been all over the internet for a while trying to find a good solution to this.
You could also try adding a custom Relay Network Layer that renders the loading indicator component on every request. I think the main concern to take into account for the "global" loading indicator is about design not only of the indicator but also about its impact on the UI globally. Is it going to block the UI?, just one part of it?, will it displace the other elements up/down?, etc.
In the meantime, you can do something like:
handleSubmit(event) {
event.preventDefault();
this.setState({isLoading: true});
this.props.relay.commitUpdate(
new LoginMutation({
email: this.refs.email.value,
password: this.refs.password.value
}), {
onSuccess: response => {
Auth.login(response.login.accessToken);
const { location, router } = this.props;
if (location.state && location.state.nextPathname) {
router.replace(location.state.nextPathname)
} else {
router.replace('/')
}
},
onFailure: transaction => {
this.setState({hasError: true});
this.setState({isLoading: false});
}
}
);
}
The above is snippet is taken from here. You can see the rest of the logic in that repo.
You can create a custom spinner component in react and based on your data load status you can either show or hide the spinner.
An example for this can be -
Your Spinner component could be like this -
let SpinMe
= (
<div className="spinner-container">
<div className="loader">
<svg className="circular">
<circle className = "path"
cx = "50"
cy = "50"
r = "20"
fill = "none"
strokeWidth = "3"
strokeMiterLimit = "10"
/>
</svg>
</div>
</div>
);
This spinner component should have somewhat higher z-index than other component so that while loading is occurring user can not click other components or interact with other components.
Also in styling show some transparent dark background of spinner.
e.g
.spinner-container {
position : absolute;
background-color : rgba(12, 12, 12, 0.61);
width : 100%;
min-height : 100%;
background-size : 100% 100%;
text-align : center;
z-index : 3;
top : 0;
left : 0;
}
Now Your another component where you want to use the spinner and in this component you want to make network request.
import React from 'react';
class SpinTestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading:false
};
}
sendNetworkRequest(URL, dataToSend) {
return $.ajax({
type : 'POST',
url : URL,
data : JSON.stringify(dataToSend),
dataType : 'json'
});
}
componentDidMount() {
const URL = "test url";
const dataToSend = { param1:"val", param2:"val" };
this.setState({isLoading:true});
this.sendNetworkRequest(dataToSend)
.then(
() => {
// success response now remove spinner
this.setState({isLoading:false});
},
() => {
// error response again remove spinner and
// show error message to end user
this.setState({isLoading:false});
});
}
render() {
return (
<div>
{ this.state.isLoading ? <SpinMe/> : null }
<div>
<h1>
Remaining Component structure
or Jsx
</h1>
<p>
To be show after loading is done.
</p>
</div>
</div>
);
}
}
export default SpinTestComponent;
I ended up extending Relay's default network layer so that I could make some Flux events that my main root component listens to. This allows me to have all my loading and error message handling in one place if I so desire.
Here's my final solution. Not sure that it's the cleanest it could be, but it works quite well.
import Relay from "react-relay";
import RelayMutationRequest from "react-relay/lib/RelayMutationRequest";
import AppDispatcher from "./AppDispatcher";
export default class CustomNetworkLayer extends Relay.DefaultNetworkLayer {
constructor(uri, init)
{
super(uri, init);
}
networkLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'LOADING'
});
}
networkDoneLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'DONE_LOADING'
});
}
networkErrorEvent(error)
{
AppDispatcher.dispatch({
actionType: 'ERROR',
payload: error
});
}
sendQueries(requests)
{
this.networkLoadingEvent();
return Promise.all(requests.map(request => (
this._sendQuery(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
if (!payload.hasOwnProperty('data')) {
const error = new Error(
'Server response was missing for query ' +
`\`${request.getDebugName()}\`.`
);
this.networkErrorEvent(error);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
)
)));
}
sendMutation(request)
{
this.networkLoadingEvent();
return this._sendMutation(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
);
}
/**
* Formats an error response from GraphQL server request.
*/
static formatRequestErrors(request, errors)
{
const CONTEXT_BEFORE = 20;
const CONTEXT_LENGTH = 60;
const queryLines = request.getQueryString().split('\n');
return errors.map(({locations, message}, ii) =>
{
const prefix = (ii + 1) + '. ';
const indent = ' '.repeat(prefix.length);
//custom errors thrown in graphql-server may not have locations
const locationMessage = locations ?
('\n' + locations.map(({column, line}) =>
{
const queryLine = queryLines[line - 1];
const offset = Math.min(column - 1, CONTEXT_BEFORE);
return [
queryLine.substr(column - 1 - offset, CONTEXT_LENGTH),
' '.repeat(Math.max(0, offset)) + '^^^',
].map(messageLine => indent + messageLine).join('\n');
}).join('\n')) :
'';
return prefix + message + locationMessage;
}).join('\n');
}
static createRequestError(request, responseStatus, payload)
{
const requestType =
request instanceof RelayMutationRequest ? 'mutation' : 'query';
const errorReason = typeof payload === 'object' ?
CustomNetworkLayer.formatRequestErrors(request, payload.errors) :
`Server response had an error status: ${responseStatus}`;
const error = new Error(
`Server request for ${requestType} \`${request.getDebugName()}\` ` +
`failed for the following reasons:\n\n${errorReason}`
);
error.source = payload;
error.status = responseStatus;
return error;
}
}
then in my index.js file I do this:
Relay.injectNetworkLayer(new CustomNetworkLayer("/graphql",
{
fetchTimeout: 35000, // timeout after 35 seconds
retryDelays: [2000] // retry after 2 seconds
}));
quick note: AppDispatcher is just a flux js dispatcher, and I'm listening to those events in my main wrapper component.
hope this helps someone else out. I certainly spent too much time on this.
Also thank you to everyone who helped me come to this solution.

Categories

Resources