I am trying to upload images from my phone which is perfectly working in iOS but it failed to work in android, have tried several android devices and all could not upload image to server. Have tried all various methods that I could find in web but none is working, wondering is it a problem with my code, expo, RN or android?
React native Upload.js
import React from 'react';
import {
ActionSheetIOS,
Text,
View,
Platform,
Image,
TouchableOpacity
} from 'react-native';
import { ImagePicker } from 'expo';
import { ActionSheetProvider, connectActionSheet } from '#expo/react-native-action-sheet';
export default class TestUpload extends React.Component {
render() {
return(
<ActionSheetProvider>
<TestUploadApp />
</ActionSheetProvider>
);
}
}
#connectActionSheet
class TestUploadApp extends React.Component {
constructor(props) {
super(props)
this.state = {
imageSource: null,
imageUri: '',
imageName: '',
imageType: ''
}
}
async getPermissionAsync() {
const { CAMERA_ROLL, Permissions } = Expo;
try {
const status = await Permissions.askAsync(Permissions.CAMERA_ROLL);
return(status);
} catch(e) {
console.log(e);
}
if (status === 'granted') {
return CAMERA_ROLL.getCurrentPositionAsync({enableHighAccuracy: true});
} else {
throw new Error('Camera Roll permission not granted');
}
}
async getPermissionCamera() {
const { CAMERA, Permissions } = Expo;
try {
const status = await Permissions.askAsync(Permissions.CAMERA);
return(status);
} catch(e) {
console.log(e);
}
if (status === 'granted') {
return CAMERA.getCurrentPositionAsync({enableHighAccuracy: true});
} else {
throw new Error('Camera permission not granted');
}
}
componentDidMount() {
this.getPermissionAsync();
this.getPermissionCamera();
}
_PickImage = async() => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 4]
});
console.log(result);
if(!result.cancelled) {
let localUri = result.uri;
let filename = localUri.split('/').pop();
// Infer the type of the image
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
let source = { uri: result.uri };
this.setState({
imageSource: source,
imageUri: localUri,
imageName: filename,
imageType: type
});
}
}
_PickCamera = async() => {
let result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 4]
});
console.log(result);
if(!result.cancelled) {
let localUri = result.uri;
let filename = localUri.split('/').pop();
// Infer the type of the image
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
let source = { uri: result.uri };
this.setState({
imageSource: source,
imageUri: localUri,
imageName: filename,
imageType: type
});
}
}
_ShowActionSheet = () => {
if(Platform.OS === 'ios') {
ActionSheetIOS.showActionSheetWithOptions({
options: ['Cancel', 'Take Photo', 'Choose From Gallery'],
cancelButtonIndex: 0,
},
(buttonIndex) => {
if(buttonIndex === 1) {
this._PickCamera();
} else if (buttonIndex === 2) {
this._PickImage();
}
});
} else if(Platform.OS === 'android') {
let options = ['Choose From Gallery', 'Take Photo', 'Cancel'];
let cancelButtonIndex = 2;
this.props.showActionSheetWithOptions({
options,
cancelButtonIndex,
},
(buttonIndex) => {
if(buttonIndex === 0) {
this._PickImage();
} else if (buttonIndex === 1) {
this._PickCamera();
}
});
}
}
SignUpProfile = () => {
const { imageUri, imageName, imageType } = this.state;
if(imageUri != null && imageUri != '') {
// Upload Image
let formData = new FormData();
formData.append('photo', {
uri: imageUri,
type: imageType,
name: imageName,
});
console.log(formData);
fetch(`${global.api}data_controller/signup_profile_upload_photo`, {
method: 'POST',
body: formData,
header: {
'Content-Type': 'multipart/form-data'
}
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
}).catch((error) => {
console.error(error);
});
}
}
render() {
return(
<View>
<TouchableOpacity
onPress={this._ShowActionSheet}
>
<Image
style={{
width: 100,
height: 100,
}}
source={this.state.imageSource != null ? this.state.imageSource : require('../../assets/images/tempat_ibadah.jpg')}
/>
</TouchableOpacity>
<TouchableOpacity
onPress={ this.SignUpProfile }
>
<Text>Upload</Text>
</TouchableOpacity>
</View>
);
}
}
Backend PHP upload-photo.php
/* I am using CodeIgniter 3.1.5
* In this case I have tried several methods
*/
public function signup_profile_upload_photo() {
/* Method 1 using CI upload library */
/* Failed to upload in iOS and android */
$dir = './tmp';
if(!is_dir($dir)) {
if(mkdir($dir, 0777, TRUE)) {
$index = '<!DOCTYPE HTML><html><head><title>403 Forbidden</title></head><body><p>Directory access is forbidden.</p></body></html>';
write_file($dir . "/index.html", $index);
}
}
$config['upload_path'] = $dir;
$config['allowed_types'] = 'gif|jpg|png';
$this->load->library('upload', $config);
if($this->upload->do_upload('photo')) {
$callback['success'] = '1';
} else {
$callback['success'] = '0';
}
/* End of Method 1 */
/* Method 2, work perfectly in iOS, but not working in all android devices */
if(move_uploaded_file($_FILES['photo']['tmp_name'], './tmp/photo.jpg')) {
$callback['move'] = '1';
} else {
$callback['move'] = '0';
}
$data = json_encode($callback);
echo $data;
}
When I console.log my FormData in react native, the result are as follows:
/* Android */
/* When selecting image */
Object {
"cancelled": false,
"height": 3120,
"type": "image",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540username%252Fprojectname/ImagePicker/538f376d-9a8c-4c4b-bc7f-bf3796785cec.jpg",
"width": 3120,
}
/* After appending to FormData
FormData {
"_parts": Array [
Array [
"photo",
Object {
"name": "538f376d-9a8c-4c4b-bc7f-bf3796785cec.jpg",
"type": "image/jpg",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540username%252Fprojectname/ImagePicker/538f376d-9a8c-4c4b-bc7f-bf3796785cec.jpg",
},
],
],
}
/* iOS */
/* Selecting image */
Object {
"cancelled": false,
"height": 1125,
"type": "image",
"uri": "file:///var/mobile/Containers/Data/Application/200DE4DB-AD0D-40A2-9BF6-4C25B147B5B1/Library/Caches/ExponentExperienceData/%2540username%252Fprojectname/ImagePicker/1772B1F0-32EF-4212-8D56-374AD57535B9.png",
"width": 1122,
}
/* FormData */
FormData {
"_parts": Array [
Array [
"photo",
Object {
"name": "1772B1F0-32EF-4212-8D56-374AD57535B9.png",
"type": "image/png",
"uri": "file:///var/mobile/Containers/Data/Application/200DE4DB-AD0D-40A2-9BF6-4C25B147B5B1/Library/Caches/ExponentExperienceData/%2540username%252Fprojectname/ImagePicker/1772B1F0-32EF-4212-8D56-374AD57535B9.png",
},
],
],
}
When I tried to console.log $_FILES['photo']['tmp_name'] after uploading with iOS, it does return a value "C:/xampp/tmp/file", but when trying to console.log the file after uploading with android, it does not return any value.
Thank you all in advance
Related
I have created a barcode scanner in my react component using QuaggaJS. The scanner is meant to be used on mobile devices through the web view. It's working fine on all iPhone devices but is not scanning correctly on androids. I am guessing this is a resolution issue in the constraints but have not found a solution that works.
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import Quagga from "#ericblade/quagga2";
import adapter from "webrtc-adapter";
import LogService from "../../services/LogService";
import "./BarcodeScanner.css";
const BarcodeScanner = (props) => {
const navigate = useNavigate();
const logService = new LogService();
let mainCameraDeviceId = "";
useEffect(() => {
async function getBackDevices() {
await Quagga.CameraAccess.request();
let devices = await Quagga.CameraAccess.enumerateVideoDevices()
.then((devices) => devices)
.catch((err) => {
logService.Log("Error", "Error when enumerating video devices", err);
console.error(`${err.name}: ${err.message}`);
});
let backDevices = [];
devices.forEach((device) => {
logService.Log("Debug", "Detected Device",device);
if(device.kind.toLowerCase().includes("videoinput") && device.label.toLowerCase().includes("back")) {
backDevices.push(device);
console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
}
});
if (backDevices.length == 0 && devices.length == 1) {
backDevices.push(devices[0]);
}
logService.Log("Debug", "Detected back devices", backDevices);
mainCameraDeviceId = backDevices[backDevices.length-1].deviceId;
startQuagga();
}
getBackDevices();
}, []);
function startQuagga() {
logService.Log("Debug", "Selected camera device", mainCameraDeviceId);
let customConstraints = {
focusMode: 'continuous',
facingMode: "environment",
zoom: {min: 1.5, max: 2},
deviceId: mainCameraDeviceId,
width: 640,
height: 480
}
if(props.deviceType == "iPhone") {
customConstraints.width = { min: 480 };
customConstraints.height = { min: 1281 };
}
logService.Log("Debug", "Device Type", props.deviceType);
logService.Log("Debug", "Quagga constraints", customConstraints);
try {
Quagga.init(
{
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector("#interactive"),
constraints: customConstraints
},
locate: true,
decoder: {
readers: [
"upc_reader"
],
multiple: false
},
},
function (err) {
if (err != null) {
console.log(err);
props.onError(err);
stopScanner();
return;
}
console.log("Initialization finished. Ready to start");
Quagga.start();
}
);
} catch {
props.onError("Failed to open camera");
}
}
Quagga.onDetected((data) => {
props.onDetected(data.codeResult.code);
Quagga.stop();
});
const stopScanner = () => {
console.log("stopping Quagga");
Quagga.stop();
};
return (
<div
className="barcode-scanner viewport"
id="interactive"
>
<div className="box-overlay"></div>
</div>
);
};
export default BarcodeScanner;
i am trying to add a voice message feature to my chat app and i have a problem on playing the audio that i record.
recordAudio.js
import { onUnmounted } from 'vue'
const constraint = { audio: true }
let chunks = []
function record() {
let mediaRecorder
let stream
function close() {
// console.log(mediaRecorder?.state, 'state man')
if (mediaRecorder && mediaRecorder?.state == 'recording'){
mediaRecorder?.stop()
stream && (
stream.getTracks()
.forEach(track => track.stop())
)
}
}
onUnmounted(() => {
close()
})
async function start() {
if (navigator.mediaDevices.getUserMedia) {
const strm = await navigator.mediaDevices.getUserMedia(constraint)
// console.log(strm)
if (!strm) return false
// console.log('media', mediaRecorder)
stream = strm
mediaRecorder = new MediaRecorder(strm)
mediaRecorder.start(100)
// console.log('listingin for audio')
mediaRecorder.ondataavailable = (e) => {
// console.log(e.data)
chunks.push(e.data)
}
}
return true
}
function stop() {
close()
const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
console.log(chunks)
chunks = []
// const audioURL = URL.createObjectURL(blob)
return blob
}
return {
start,
stop
}
}
export {
record
}
this is a code fragment in a .vue file
import {record} from '#util/recordAudio.js'
const { start, stop } = record()
async function recordAudio() {
if (!recording.value) {
let res = await start()
res && (recording.value = true)
} else {
stop()
recording.value = false
}
}
function sendAudio() {
let audioBlob = stop()
recording.value = false
console.log(audioBlob)
messages.addMessage({
id: props.chat.id,
message: {
id: 1,
to: 2,
from: 1,
message: audioBlob,
seen: true,
type: 'audio',
createdAt: new Date()
}
})
}
let url = {}
function getObjectUrl(id, message) {
if (!url[id]) {
url[id] = URL.createObjectURL(message)
return url[id]
}
return url[id]
}
//this is the template for the audio
<div v-if='message.type == "audio"'>
<audio controls :src='getObjectUrl(message.id, message.message)'></audio>
</div>
it seems to work for the first time and it doesnt work after.
in firefox i get the warning/error
Media resource blob:http://localhost:5374/861d13c5-533f-4cd7-8608-68eecc7deb4e could not be decoded
Media resource blob:http://localhost:5374/861d13c5-533f-4cd7-8608-68eecc7deb4e could not be decoded, error: Error Code: NS_ERROR_DOM_MEDIA_METADATA_ERR (0x806e0006)
error message
I want to analyze a lot of urls in short period.
For analyze the urls, I am using Wappalyzer module.
Piscina is what I chose for speed optimization and it is working well.
However, I am not satisfied with the current speed and I need faster one.
Here is my current code.
index.js
const Piscina = require("piscina");
const { program } = require("commander");
const { readCsv, cleanFile } = require("./src/csv");
const { resolve, join } = require("path");
const { chunks } = require("./src/utils");
async function run({
chunksNum = 500,
enableLogging = true,
inputFile,
outputFile,
enableConfidence = false,
limitTab = 5,
}) {
console.time("Analyze time");
const inputFileLocation = join(__dirname, inputFile);
const outputFileLocation = join(__dirname, outputFile);
console.log("Reading input csv file...");
let urls = await readCsv(inputFileLocation);
// urls = urls.slice(0, 1)
console.log(`* Done!, total urls will be analyzed: ${urls.length}`);
try {
const urlChunks = chunks(urls, chunksNum);
console.log(`* Total threads: ${urlChunks.length}`);
const pool = new Piscina({
filename: resolve(__dirname, "./src/worker-pool.js"),
});
console.log("Start analyzing...");
await cleanFile(outputFileLocation);
await Promise.all(
urlChunks.map((urls, index) => {
console.log(`-- Thread ${index} will analyze ${urls.length} urls`);
return pool.run({
urls,
enableLogging,
limitTab,
threadIndex: index,
outputFile: outputFileLocation,
});
})
);
console.log("Writing results to csv...");
// await writeCsv(outputFileLocation, results.flat(), enableConfidence)
console.log("Writing results done!");
} catch (error) {
console.error(error);
}
console.timeEnd("Analyze time");
}
program
.option("-c, --chunks <number>", "Split urls into n chunks (default 1000)")
.option(
"-lm, --limitTab <number>",
"Limit chrome tabs per chrome instance (default 10)"
)
.option("-l, --log", "Enable logging (default false)")
.option("-i, --input <file>", "Input file (default urls.csv)")
.option("-o, --output <file>", "Input file (default result.csv)")
.option(
"-cfd, --confidence",
"Write confidence results to csv (default false)"
);
program.parse(process.argv);
const options = program.opts();
const chunksNum = parseInt(options.chunks) || 1000;
const enableLogging = options.log || false;
const enableConfidence = options.confidence || false;
const limitTab = parseInt(options.limitTab) || 10;
const inputFile = options.input || "urls.csv";
const outputFile = options.output || "result.csv";
run({
chunksNum,
enableLogging,
inputFile,
outputFile,
enableConfidence,
limitTab,
});
package.json
{
"name": "wappalyzer",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^9.2.0",
"csv": "^6.0.5",
"piscina": "^3.2.0",
"wappalyzer": "^6.10.23"
}
}
urls.csv
akwam.io
bciseguros.cl
ctctusercontent.com
haodeplus.com
aicaimei.com
papik.pro
prixdubaril.com
cambiumast.com
fyeds2.com
jimcontent.com
dbankcloud.com
sura.cl
tazkarti.com
coke.com
secureholiday.net
petycjeonline.com
aso1.net
ookla.com
samsungpromotions.claims
shec.edu.cn
tui.ch
filmstreaming.al
bttba.com
guizumeimei.com
xiti.com
wakefern.com
housingauthority.gov.hk
quantserve.com
jabama.com
lord-film-cc.me
xiepp.cc
yourcovidrecovery.nhs.uk
leyuman.com
jse.edu.cn
kkkkwu.com
pingit.im
service-voyages.com
fiaformula2.com
junaeb.cl
yt.be
windowssearch-exp.com
tickets.com
manga1002.com
yuedyue.com
nakadashi.pw
tapmad.com
mywelfare.ie
freemangaraw.com
shukriya90.com
regudri.xyz
pgmall.my
secsso.net
uab.cat
job-terminal.com
swimsuitsforall.com
sberbank.com
vic.gov.au
hondadealers.com
mptgate.com
hgq26.com
lenzmx.com
minna-no-ginko.com
vchecks.io
feed-xml.com
optoutsub.net
mengyuanshucheng.com
utiitsl.com
beneficiosestudiantiles.cl
adpool.bet
csdiran.ir
aftrk3.com
100fanwo.com
bancolombia.com
binaamanhaji.com
tokyo-brain.clinic
tcloudbaseapp.com
qimiaomh.com
12cm.com.tw
amplifyapp.com
86zw.co
infinitummovil.net
sejam.ir
maeva.com
ghiseul.ro
sf024.com
capcut.net
fusetracking.com
mof.gov.cn
northgate-nes.co.uk
btbtt20.com
srvpcn.com
downxia.com
googleweblight.com
ajuda.globo
likecs.com
... more than 8970
src/analyse.js
async function analyzeUrl(wappalyzerInstance, url, enableLogging = false) {
// check if the url string has a protocol, if not, add http://
if (!url.startsWith('http')) {
url = `http://${url}`
}
if (enableLogging) {
console.log('------ Start analyzing: ', url)
}
const site = await wappalyzerInstance.open(url)
const results = await site.analyze()
const detectResult = await detectSpotifyOrStripeInTechnologies(results.technologies)
if (enableLogging) {
console.log(`------ Finish analyzing: ${url}; Result: ${detectResult.exist ? `Found ${detectResult.label}!` : 'Not found.'}`)
}
src/csv.js
const fs = require('fs')
const { parse, stringify } = require('csv')
async function readCsv(csvFile) {
const urls = []
// read the csv file
const parser = parse({ columns: false })
const stream = fs.createReadStream(csvFile).pipe(parser)
stream.on('data', (row) => {
urls.push(row[0])
})
// wait for the stream to end and return the urls
await new Promise((resolve) => {
stream.on('end', () => {
resolve(urls)
})
})
return urls
}
//RETURN CSV
function generateOutputData(data, enableConfidence) {
const outputData = data.map(row => {
if (row.technologies) {
return { url: row.url.slice(7), detect: row.technologies, confidence: row.confidence }
}
return { url: row.url, detect: row.label || '-' }
})
return outputData
}
async function cleanFile(outputFile) {
await fs.writeFileSync(outputFile, '', 'utf-8')
}
async function writeCsv(outputFile, data, enableConfidence) {
const outputData = generateOutputData(data, enableConfidence)
stringify(outputData, { header: true }, (err, output) => {
if (err) {
console.error(err)
}
fs.writeFile(outputFile, output, (err) => {
if (err) {
console.error(err)
}
})
})
}
async function appendCsv(outputFile, data, enableConfidence) {
const outputData = generateOutputData(data, enableConfidence)
stringify(outputData, { header: false }, (err, output) => {
if (err) {
console.error(err)
}
fs.appendFile(outputFile, output, (err) => {
if (err) {
console.error(err)
}
})
})
}
module.exports = {
readCsv, writeCsv, appendCsv, cleanFile
}
return {
url, ...results
}
}
module.exports = { analyzeUrl }
src/utils.js
function chunks(arr, chunkSize) {
if (chunkSize === 0) return arr
let results = [];
while (arr.length) results.push(arr.splice(0, chunkSize));
return results;
}
module.exports = { chunks };
src/worker-pool.js
const Wappalyzer = require("wappalyzer");
const { analyzeUrl } = require("./analyze");
const { chunks } = require("./utils");
const { appendCsv } = require("./csv");
module.exports = async ({
urls,
enableLogging,
limitTab = 5,
threadIndex,
outputFile,
}) => {
const options = {
debug: false,
delay: 5000,
maxDepth: 3,
maxUrls: 3,
maxWait: 10000,
recursive: true,
userAgent: "Wappalyzer",
};
const urlChunks = chunks(urls, limitTab);
const results = [];
let finishUrl = 0;
for (let chunk of urlChunks) {
console.log("---- Create new chrome instance");
const wappalyzer = new Wappalyzer(options);
await wappalyzer.init();
console.log(`---- Open ${chunk.length} tabs in thread ${threadIndex}`);
const result = await Promise.all(
chunk.map((url) => analyzeUrl(wappalyzer, url, enableLogging))
);
await appendCsv(outputFile, result.flat(), false);
finishUrl += chunk.length;
const totalUrls = urlChunks.flat().length;
console.log(
`---- Finish ${finishUrl}/${totalUrls} urls in thread ${threadIndex}`
);
results.push(result);
await wappalyzer.destroy();
console.log("---- Destroy chrome instance");
}
console.log(`-- Finish thread ${threadIndex}`);
return results.flat();
};
I have a MQTTConnection.js class inside a src folder this class defines methods like subscribe, unsubsribe and connect. Also the App.js class implements the methods imported from MQTTConnection.js and defines the prototypes functions that start with ONMQTT. When I try to run the project the next error is displayed : TypeError: _this.onMQTTLost is not a function.
App.js
import MQTTConnection from './src/MQTTConnection'
import React, {
useEffect
} from 'react'
import {
View,
StyleSheet,
Text,
Button
} from 'react-native'
import {
Buffer
} from 'buffer';
global.Buffer = Buffer;
export default function App() {
useEffect(() => {
this.mqttConnect = new MQTTConnection()
this.mqttConnect.onMQTTConnect = this.onMQTTConnect
this.mqttConnect.onMQTTLost = this.onMQTTLost
this.mqttConnect.onMQTTMessageArrived = this.onMQTTMessageArrived
this.mqttConnect.onMQTTMessageDelivered = this.onMQTTMessageDelivered
onMQTTConnect = () => {
console.log('App onMQTTConnect')
this.mqttConnect.subscribeChannel('hanth2')
}
onMQTTLost = () => {
console.log('App onMQTTLost')
}
onMQTTMessageArrived = (message) => {
console.log('App onMQTTMessageArrived: ', message);
console.log('App onMQTTMessageArrived payloadString: ', message.payloadString);
}
onMQTTMessageDelivered = (message) => {
console.log('App onMQTTMessageDelivered: ', message);
}
this.mqttConnect.connect('4924d328ffbe4e649e261db3563eed0a.s2.eu.hivemq.cloud', 8884)
return () => {
this.mqttConnect.close()
}
}, [])
return ( <
View style = {
styles.container
} >
<
Text > react_native_mqtt < /Text> <
Button title = "Press me"
onPress = {
() => this.mqttConnect.send('hanth2', "message send to channel hanth2 again")
}
/> <
/View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
})
MQTTConnection.js
import init from 'react_native_mqtt';
import uuid from 'react-native-uuid';
import AsyncStorage from '#react-native-community/async-storage';
init({
size: 10000,
storageBackend: AsyncStorage,
defaultExpires: 1000 * 3600 * 24,
enableCache: true,
sync: {},
});
const defaultConnectOptions = {
reconnect: false,
cleanSession: true,
mqttVersion: 3,
keepAliveInterval: 60,
timeout: 60,
userName: 'serjaumen22',
password: ''
}
export default class MQTTConnection {
constructor() {
this.mqtt = null;
this.QOS = 0;
this.RETAIN = true;
}
connect(host, port, options = null) {
if (options) {
this.QOS = options.qos;
this.RETAIN = options.retain;
}
let currentTime = +new Date();
let clientID = currentTime + uuid.v1();
clientID = clientID.slice(0, 23);
console.log('clientID: ', clientID)
this.mqtt = new Paho.MQTT.Client(host, port, clientID);
this.mqtt.onConnectionLost = (res) => {
this.onMQTTLost;
};
this.mqtt.onMessageArrived = (message) => {
this.onMQTTMessageArrived(message);
};
this.mqtt.onMessageDelivered = (message) => {
this.onMQTTMessageDelivered(message);
};
const connectOptions = options ? options : defaultConnectOptions;
this.mqtt.connect({
onSuccess: this.onMQTTSuccess,
onFailure: this.onMQTTFailure,
...connectOptions
});
}
onMQTTSuccess = () => {
this.onMQTTConnect()
}
onMQTTFailure = () => {
this.onMQTTLost()
}
subscribeChannel(channel) {
console.log('MQTTConnection subscribeChannel: ', channel)
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
this.mqtt.subscribe(channel, this.QOS);
}
unsubscribeChannel(channel) {
console.log('MQTTConnection unsubscribeChannel: ', channel)
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
this.mqtt.unsubscribe(channel);
}
send(channel = null, payload) {
console.log('MQTTConnection send: ')
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
if (!channel || !payload) {
return false;
}
console.log(`MQTTConnection send publish channel: ${channel}, payload: ${payload} qos: ${this.QOS} retained: ${this.RETAIN}`)
this.mqtt.publish(channel, payload, this.QOS, this.RETAIN);
}
close() {
this.mqtt && this.mqtt.disconnect();
this.mqtt = null;
}
}
MQTTConnection.prototype.onMQTTConnect = null
MQTTConnection.prototype.onMQTTLost = null
MQTTConnection.prototype.onMQTTMessageArrived = null
MQTTConnection.prototype.onMQTTMessageDelivered = null
I want to save an array of object to device using AsyncStorage, I have used AsyncStorage for save my jwt token and it working well. But when i tried to save an array of object it wasn't working here is my code :
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
setCarts(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
I have tried to console log the result after setItem, and it was saved successly, but when i reload the app and tried to console.log, it return and empty array, the key is already correct, and i have console log the user id too for make sure.
Here's the full code, if needed :
import React, { useState, createContext, useEffect, useContext } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import AuthenticationContext from '../authentication/AuthenticationContext';
const CartsContext = createContext();
export const CartsContextProvider = ({ children }) => {
const { user } = useContext(AuthenticationContext);
const [carts, setCarts] = useState([]);
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
setCarts(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
useEffect(() => {
storeCart(carts);
}, [carts, user]);
useEffect(() => {
getCart();
}, [user]);
const searchByMerchant = (merchantId) => {
for (let i = 0; i < carts.length; i++) {
if (carts[i].merchantId === merchantId) {
return carts[i];
}
}
};
const searchByItem = (itemId, arrayOfItems) => {
for (let i = 0; i < arrayOfItems.length; i++) {
if (itemId === arrayOfItems[i].productId) {
return arrayOfItems[i];
}
}
};
const deletePerMerchant = (merchantId) => {
return carts.filter((x) => {
return x.merchantId != merchantId;
});
};
const deletePerItem = (itemId, arrayOfItems) => {
return arrayOfItems.filter((x) => {
return x.productId != itemId;
});
};
const addItem = (merchantId, productId, qty) => {
let merchantCheck = searchByMerchant(merchantId);
let temp = null;
if (merchantCheck) {
let itemCheck = searchByItem(productId, merchantCheck.items);
if (itemCheck) {
let itemAfterRemoveSelectedItem = deletePerItem(
productId,
merchantCheck.items,
);
temp = deletePerMerchant(merchantId);
if (qty === 0) {
if (itemAfterRemoveSelectedItem.length === 0) {
setCarts([...temp]);
} else {
setCarts([
...temp,
...[
{
merchantId,
items: [...itemAfterRemoveSelectedItem],
},
],
]);
}
} else {
setCarts([
...temp,
...[
{
merchantId,
items: [
...itemAfterRemoveSelectedItem,
...[{ productId, qty: qty }],
],
},
],
]);
}
} else {
temp = deletePerMerchant(merchantId);
setCarts([
...temp,
...[
{
merchantId,
items: [...merchantCheck.items, ...[{ productId, qty }]],
},
],
]);
}
} else {
if (qty > 0) {
setCarts([...carts, ...[{ merchantId, items: [{ productId, qty }] }]]);
}
}
};
return (
<CartsContext.Provider value={{ carts, addItem }}>
{children}
</CartsContext.Provider>
);
};
export default CartsContext;
Thanks !
I believe this is happening because the cart value is being overwritten when you reload the app because the useEffect is called each time you reload the app.
The setCarts is being called after adding something in cart, and therefore the first useEffect (which has in deps [cart, user]) is being called too and it sets correctly the data in local storage. But afterwards, if you reload the app, the same useEffect is being called again and the cart = [] is being set into the local storage.
I would solve this by giving up to the first useEffect and setting directly the data into local storage without having any state related to it.
import React, { useState, createContext, useEffect, useContext } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import AuthenticationContext from '../authentication/AuthenticationContext';
const CartsContext = createContext();
export const CartsContextProvider = ({ children }) => {
const { user } = useContext(AuthenticationContext);
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
storeCart(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getCart();
}, [user]);
const searchByMerchant = (merchantId) => {
for (let i = 0; i < carts.length; i++) {
if (carts[i].merchantId === merchantId) {
return carts[i];
}
}
};
const searchByItem = (itemId, arrayOfItems) => {
for (let i = 0; i < arrayOfItems.length; i++) {
if (itemId === arrayOfItems[i].productId) {
return arrayOfItems[i];
}
}
};
const deletePerMerchant = (merchantId) => {
return carts.filter((x) => {
return x.merchantId != merchantId;
});
};
const deletePerItem = (itemId, arrayOfItems) => {
return arrayOfItems.filter((x) => {
return x.productId != itemId;
});
};
const addItem = (merchantId, productId, qty) => {
let merchantCheck = searchByMerchant(merchantId);
let temp = null;
if (merchantCheck) {
let itemCheck = searchByItem(productId, merchantCheck.items);
if (itemCheck) {
let itemAfterRemoveSelectedItem = deletePerItem(
productId,
merchantCheck.items,
);
temp = deletePerMerchant(merchantId);
if (qty === 0) {
if (itemAfterRemoveSelectedItem.length === 0) {
storeCart([...temp]);
} else {
storeCart([
...temp,
...[
{
merchantId,
items: [...itemAfterRemoveSelectedItem],
},
],
]);
}
} else {
storeCart([
...temp,
...[
{
merchantId,
items: [
...itemAfterRemoveSelectedItem,
...[{ productId, qty: qty }],
],
},
],
]);
}
} else {
temp = deletePerMerchant(merchantId);
storeCart([
...temp,
...[
{
merchantId,
items: [...merchantCheck.items, ...[{ productId, qty }]],
},
],
]);
}
} else {
if (qty > 0) {
storeCart([...carts, ...[{ merchantId, items: [{ productId, qty }] }]]);
}
}
};
return (
<CartsContext.Provider value={{ carts, addItem }}>
{children}
</CartsContext.Provider>
);
};
export default CartsContext;