Write files to directory error - Expo FileSystem - react-native

I am really struggling to find where I am going wrong with this. I am trying to move the picked (ImagePicker) image from cache to app scope directory folder named images/. I created a directory images/ using FileSystem.makeDirectoryAsync but while trying to move the picked image to this directory I am getting an error. Please can someone help me I am really struggling
Expected Result
The image successfully moves to the images/ directory
Actual Result
[Unhandled promise rejection: Error: File 'file:///var/mobile/Containers/Data/Application/318CFCE4-16DF-44DD-92B3-39DECA61EA14/Library/Caches/ExponentExperienceData/%2540user%252FtestApp/ImagePicker/ECD218AE-3DD3-429F-B1F5-469DA1AC661C.jpg' could not be moved to
'file:///var/mobile/Containers/Data/Application/318CFCE4-16DF-44DD-92B3-39DECA61EA14/Documents/ExponentExperienceData/%2540user%252FtestApp/images/ECD218AE-3DD3-429F-B1F5-469DA1AC661C.jpg/'.]
This is my code:
import React, { useEffect, useState } from "react";
import {Text,View,TouchableOpacity,Alert,} from "react-native";
import * as ImagePicker from "expo-image-picker";
import * as Permissions from "expo-permissions";
import * as FileSystem from "expo-file-system";
const ImageCard = (props) => {
const { handlePickedImage } = props;
const [image, setImage] = useState("");
// Create any app folders that don't already exist
export const checkAndCreateFolder = async folder_path => {
const folder_info = await FileSystem.getInfoAsync(folder_path);
if (!Boolean(folder_info.exists)) {
// Create folder
console.log("checkAndCreateFolder: Making " + folder_path);
try {
await FileSystem.makeDirectoryAsync(folder_path, {
intermediates: true
});
} catch (error) {
// Report folder creation error, include the folder existence before and now
const new_folder_info = await FileSystem.getInfoAsync(folder_path);
const debug = `checkAndCreateFolder: ${
error.message
} old:${JSON.stringify(folder_info)} new:${JSON.stringify(
new_folder_info
)}`;
console.log(debug);
}
}
};
const veryfiyPermissons = async () => {
const result = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (result.status !== "granted") {
Alert.alert(
"Insufficient permissions",
"You need to grant permissions to access Camera Roll",
[{ text: "Okay" }]
);
return false;
}
return true;
};
const selectImageHandler = async () => {
const hasPermisson = await veryfiyPermissons();
if (!hasPermisson) {
return;
}
const image = await ImagePicker.launchImageLibraryAsync({
quality: 0.5,
});
if (image.cancelled) {
randomImage;
} else {
let localUri = image.uri;
let localUriNamePart = localUri.split("/");
const fileName = localUriNamePart[localUriNamePart.length - 1];
const images_folder = `${FileSystem.documentDirectory + 'images/'}`
checkAndCreateFolder(images_folder);
const setTheFile = `${images_folder + `${fileName}/`}`
await FileSystem.moveAsync({
from: localUri,
to: newLocation
}).then((i) => {
setImage(setTheFile);
handlePickedImage(setTheFile);
})
}
};
return (
<View>
<TouchableOpacity onPress={selectImageHandler}>
<Text>Add Photo</Text>
</TouchableOpacity>
</View>
);
};
export default ImageCard;

Related

React Native useEffect not run when app first opened

I am trying to make an app where the USER_ID is loaded from the device's local storage if found, otherwise, a new id is generated and stored in the local storage. I am trying to make use of React useContext() to make the USER_ID visible to the whole app after it is first run.
import React, {useEffect, useState} from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
export const UserIdContext = React.createContext('undef');
export const UserIdProvider = ({children}) => {
const [userId, setUserId] = useState('');
useEffect(() => {
async function getOrInitUserId() {
try {
let temp = await AsyncStorage.getItem('USER_ID');
if (temp == null) {
temp = uuid.v4();
await AsyncStorage.setItem('USER_ID', uuid.v4());
console.log('USER_ID Generated: ' + temp);
} else {
console.log('USER_ID Found: ' + temp);
}
setUserId(temp);
} catch (error) {
console.error(error);
}
}
if (!userId) {
getOrInitUserId();
}
});
return (
<UserIdContext.Provider value={userId}>{children}</UserIdContext.Provider>
);
};
export const useUserId = () => React.useContext(UserIdContext);
The provider is used as below:
const App = () => {
useEffect(() => {
....
});
return (
<UserIdProvider>
...contents of app...
</UserIdProvider>
);
};
export default App;
However, the useEffect() of < UserIdProvider /> is not run as the app is launched for the first time after being installed on a device, as there is no log on the console. After the app is closed/quit and relaunched, the console log a USER_ID found, instead of USER_ID generated.
Add 2nd argument as [] so it will render only once. Otherwise, it will render every time when any state will be updated.
const App = () => {
useEffect(() => {
....
},[]);
return (
<UserIdProvider>
...contents of app...
</UserIdProvider>
);
};
export default App;
In order to trigger useEffect when first run you should enter [] as prop like this:
useEffect(() => {
async function getOrInitUserId() {
try {
let temp = await AsyncStorage.getItem('USER_ID');
if (temp == null) {
temp = uuid.v4();
await AsyncStorage.setItem('USER_ID', uuid.v4());
console.log('USER_ID Generated: ' + temp);
} else {
console.log('USER_ID Found: ' + temp);
}
setUserId(temp);
} catch (error) {
console.error(error);
}
}
if (!userId) {
getOrInitUserId();
}
}, []);

React Native: How to add items to the set state of useState for getting socket notifications?

I need a function for getting notification from socket (TypeScript) .
For instance ,
when a user click the "Like",the receiver will receive a notice like "You have receive a like from XXX",and I am able to get this message from the below code ,however ,I am not sure how to save those notifications into a list in order to display all the notices ..Could you please take a look how to do it ? Thank you so much in advance !!
I have putted the socket in the useContext :
import React from 'react';
import socketio from 'socket.io-client';
export const socket = socketio.connect(SOCKET_URL);
export const SocketContext = React.createContext();
When I send click a like, the receiver can receive my notification, and then the remark in the below codes,I can't get the notification list :
import {SocketContext} from '../../auth/context';
import React, {useEffect, useState, useContext, useLayoutEffect} from 'react';
const Home = () =>{
const {socket, user} = useContext(SocketContext);
const [notificationCount, setNotificationCount] = useState([]);
const [me, setMe] = useState({});
// init data
const initialData = async () => {
try {
const meResult = await fetchGetMe();
setMe(meResult?.data.data);
} catch (error) {
console.log('initial data get errors:', error);
}
};
useLayoutEffect(() => {
initialData();
}, []);
//get feedback from socket
useEffect(() => {
socket.on('getNotification', data => {
setNotificationCount(pre=> [...pre, data]); //I got the problem here..Can't get the list
console.log('notification data :', notificationCount);
});
return () => {
socket.off('getNotification');
};
}, [socket]);
const onPressLike = ()=>{
socket.emit('sendNotification', {
senderUserId: me?.userId,
senderName: me?.userName,
receiverUserId: 123456,
type: 0, // 0:like 1.gifts 2.sunflower
});
}
<Button onClick={onPressLike}>Like</Button>
}
3.My socket config in the server part :
let onlineUsers = [];
const addUsers = (userId, socketId) => {
!onlineUsers.some((m) => m.userId !== userId) &&
onlineUsers.push({ userId, socketId });
};
const removeUser = (socketId) => {
onlineUsers = onlineUsers.filter((user) => user.socketId !== socketId);
};
const getUser = (receiverId) => {
return onlineUsers.find((m) => m.userId === receiverId);
};
io.on("connection", (socket) => {
console.log("connect now");
socket.on("newUser", (userId) => {
addUsers(userId, socket.id);
console.log("onlineUsers:", onlineUsers);
});
socket.on(
"sendNotification",
({ senderUserId, senderName, receiverUserId, type }) => {
console.log(
`senderName:${senderName},receiverID:${receiverUserId};type:${type},socketId:${socket.id};senderUserId:${senderUserId}`
);
console.log("sendNotification,onlineUsers:", onlineUsers);
let receiver = {};
if (onlineUsers.length > 0) {
receiver = getUser(senderUserId);
console.log("receiver:", receiver);
io.to(receiver.socketId).emit("getNotification", {
senderName,
type,
});
} else {
receiver = null;
console.log("receiver:", receiver);
socket.emit("getNotification", { receiver });
}
}
);
socket.on("disconnect", () => {
console.log("disconnect");
});
});

UseEffect with getPermissionAsync

unfortunately I am struggling with the hook lifecycle in react native.
I have two hooks at the top level.
const permission = useLocationPermission();
const location = useCurrentLocation(locationPermission);
The first one handles the location permission permission and asks the user to grand.
export default function useLocationPermission() {
const [hasLocationPermission, setHasLocationPermission] = useState(false);
const appState = useRef(AppState.currentState);
useEffect(() => {
hasPermission();
}, []);
const hasPermission = async () => {
const { granted } = await Location.getForegroundPermissionsAsync();
if (!granted) {
const { granted: request } =
await Location.requestForegroundPermissionsAsync();
if (!request) {
Alert.alert(
"Some Message"
);
setHasLocationPermission(false);
} else {
setHasLocationPermission(true);
}
} else {
setHasLocationPermission(true);
}
};
return hasLocationPermission;
}
The second one handles the current location.
export default function useCurrentLocation(hasPermission: boolean) {
const [currentLocation, setCurrentLocation] = useState<LatLng>(initLocation);
useEffect(() => {
console.log(hasPermission);
if (hasPermission) {
setWatcher();
getCurrentPosition().then((locationObject) => {
setCurrentLocation({
latitude: locationObject.coords.latitude,
longitude: locationObject.coords.longitude,
});
});
} else {
setCurrentLocation(initLocation);
}
}, []);
const getCurrentPosition = async () => {
return Location.getCurrentPositionAsync({});
};
const setWatcher = async () => {
await Location.watchPositionAsync({ distanceInterval: 5 }, (locaction) => {
setCurrentLocation({
latitude: locaction.coords.latitude,
longitude: locaction.coords.longitude,
});
});
};
return currentLocation;
}
My problem is that after the user has granted the permission. The location will not been updated anymore (still the initial location). It seems that the second hook is only called ones.
Is there any best practice to handle such situation. So the location will be updated and the watcher is set after the permission is set.
Thanks a lot.
Your list of dependencies for the effect that sets current location is empty. Since you are saying you want that effect to be dependant on hasPermission, set it to [hasPermission] instead.

observable and computed not being reflected in a functional component

I am learning mobx for react-native and not able to see changes to done to observables or computed.
Basically, I want to listen to changes to observable from the component.
My store is simple:
import { observable, action, computed } from 'mobx';
import AsyncStorage from '#react-native-async-storage/async-storage';
class ConfigStore {
rootStore = undefined;
#observable activeConfig = {group: 'starter', TC: false};
constructor(rootStore) {
this.rootStore = rootStore;
}
#computed get termsLoaded(){
return this.activeConfig.TC;
}
#action async loadPreviousConfig() {
const configDetails = { group: 'starter', TC: false};
try {
const response = await AsyncStorage.multiGet([
'group',
'TC'
]);
configDetails.group = response[0][1] || 'starter';
configDetails.TC = response[1][1] === undefined ? false : true;
console.log(configDetails);// shows correct previously saved config
this.activeConfig = configDetails;
} catch (error) {}
}
}
export default ConfigStore;
From my component, I want to load first previous configuration settings and have them reflect in my app. Basically, I want to check the value of TC ater calling loadPreviousConfig, they return false still:
import { inject, observer } from 'mobx-react';
const ConfigComponent = (props) => {
const { store } = props;
const { termsLoaded, activeConfig, loadPreviousConfig } = store.configStore;
useEffect(() => {
const init = async () => {
await loadPreviousConfig();
console.log(termsLoaded); //always false even though console from the store shows it is true.
};
init();
}, []); //tried [props]
return (
<View>
<Text>{activeConfig.group}</Text> //never changes
</View>
);
};
export default inject('store')(observer(ConfigComponent));

React Native - How to update a value for entire application

What is the best way to find a value in the api request and make it available in the entire application? I need to get the total of unread messages and show it to the user in the application header. Every time you change pages, a new request is made to update the total of unread messages. I'm using a context like this:
/** #format */
import React, { createContext, useContext, useState, useEffect, useRef } from "react";
import AsyncStorage from "#react-native-async-storage/async-storage";
import api from "../services/api";
const BadgeContext = createContext();
export default function BadgeProvider({ children }) {
const [messageCount, setMessageCount] = useState(0);
const [userLogged, setUserLogged] = useState("");
async function getAuthUserFromStorage() {
try {
const dataFromStorage = await AsyncStorage.getItem("#ellot:authUserLogged");
const authUserLogged = JSON.parse(dataFromStorage);
setUserLogged(authUserLogged.user);
} catch (e) {
console.log("ERROR: ", e);
}
}
useEffect(() => {
getAuthUserFromStorage();
}, []);
useEffect(() => {
const getTotalMessageNotRead = async () => {
try {
const response = await api.get(`/messages/total-not-read/${userLogged.id}`);
setMessageCount(response.data.data);
console.log("messageCount context ", messageCount);
} catch (error) {
console.log("Message Not Read Error: ", error);
} finally {
console.log("finally message not reader context", messageCount);
}
};
getTotalMessageNotRead();
}, []);
async function resetCountMessage() {
setMessageCount(0);
}
const store = {
messageCount,
resetCountMessage,
};
return <BadgeContext.Provider value={store}>{children}</BadgeContext.Provider>;
}
export function useBadge() {
const context = useContext(BadgeContext);
const { messageCount, resetCountMessage } = context;
return { messageCount, resetCountMessage };
}