Data lost with last version of react-native and AsyncStorage - react-native

When I try to update my application (android/ios) with react-native and expo my data is lost and i don't know why :
old version :
"react-native": "0.51.0",
"redux-persist": "4.8.2",
new version :
"redux-persist": "4.8.2",
"react-native": "~0.61.5",
"expo": "^37.0.12",
Build with expo for the newer version
How I persist the data. The code hasn't changed between versions.
useEffect(() => {
persistStore(
store,
{
storage: AsyncStorage,
whitelist: ['data', 'data2' ],
transforms: [
createTransform(
state => state,
state => ({
...state,
infosOpened: false,
}),
{
whitelist: 'app',
}
),
],
},
() => {
setRehydrated(true)
}
)
}, [])
AsyncStorage is imported from react-native and I keep react-native with expo. #react-native-community/async-storage isn't compatible.
As what I saw inside the older version data is persisted with SQLlite format 3 inside "data user". Data appears to be always here with the newer version but it is no longer recovered.
I don't know if there is some braking changes react-native from version 51 to 61. I see nothing inside github release tags.
Edit1: OK so it seems that the problem is that RN use RCTAsyncLocalStorage_V1 folder and expo RCTAsyncLocalStorage. How I can fix that with the easiest way for IOS and Android ? Is it better to eject expo app or to add migration code ?
Edit2: Finally I opted for an RN version with react-native-unimodules like that I have no problem with path storage and I can use some dependencies from expo. (https://blog.expo.io/you-can-now-use-expo-apis-in-any-react-native-app-7c3a93041331)
Maybe the solution under works... I didn't test it
Another possible solution here. I didn't test it too :
https://github.com/expo/expo/issues/8220#issuecomment-656300244

You can find the sample code for migration in the snippet. This snippet is migration from Expo to pure RN. You will only have to reverse migration.
import React, { Component } from 'react';
import { View, ActivityIndicator, AsyncStorage } from 'react-native';
import PropTypes from 'prop-types';
import RNFS from 'react-native-fs';
export default class WalletMigrate extends Component {
componentDidMount() {
this.migrateDataFromExpo();
}
migrationComplete() {
console.log('Migration was successful. Exiting migration...')
this.props.onComplete();
}
// Migrate Document directory from Expo
async migrateDataFromExpo() {
const expoDirectoryExists = await RNFS.exists(RNFS.DocumentDirectoryPath + '/ExponentExperienceData');
if (!expoDirectoryExists) {
console.log('Expo data was previously migrated. Exiting migration...');
this.props.onComplete();
return;
}
try {
await RNFS.unlink(RNFS.DocumentDirectoryPath + '/RCTAsyncLocalStorage_V1')
console.log('/RCTAsyncLocalStorage_V1 has been deleted. Continuing...')
} catch {
console.log('/RCTAsyncLocalStorage_V1 does not exist. Continuing...')
}
RNFS.copyFile(
RNFS.DocumentDirectoryPath + '/ExponentExperienceData/%40USERNAME%2FAPPNAME/RCTAsyncLocalStorage',
RNFS.DocumentDirectoryPath + '/RCTAsyncLocalStorage_V1',
)
.then(() => {
RNFS.readDir(RNFS.DocumentDirectoryPath + '/RCTAsyncLocalStorage_V1').then(files => {
files.forEach(file => {
if (file.name !== 'manifest.json') {
RNFS.readFile(file.path).then(fileContents => {
AsyncStorage.setItem('data', fileContents)
.then(() => {
RNFS.unlink(RNFS.DocumentDirectoryPath + '/ExponentExperienceData').then(() => this.migrationComplete());
})
.catch(() => {
console.log('An error was encountered when trying to delete /ExponentExperienceData. Exiting migration...');
this.props.onComplete();
})
.then(() => this.migrationComplete())
});
}
});
})
.catch(error => {
console.log('An error was encountered when trying to read the /RTCAsyncLocalStorage_V1 directory. Exiting migration...');
console.log(error);
this.props.onComplete();
});
})
.catch(_error => this.props.onComplete());
}
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignContent: 'center' }}>
<ActivityIndicator />
</View>
);
}
}
WalletMigrate.propTypes = {
onComplete: PropTypes.func,
};

Related

ConnectyCube expo react native support for RNChat

Is there a chance to get an RNChat example which runs on latest expo react native for supporting the great expo plugins like expo av player or expo haptics?
Edit:
Build fails
=== BUILD TARGET React-Codegen OF PROJECT Pods WITH CONFIGURATION Debug ===
Check dependencies
** BUILD FAILED **
The following build commands failed:
CompileSwiftSources normal x86_64 com.apple.xcode.tools.swift.compiler
CompileSwift normal x86_64
(2 failures)
I get tons of errors using the expo and expo-modules-core like:
expo-modules-core/ Class Components Factories swift:71:52: error: unknown attribute '_implicitSelfCapture'
OR
expo-modules-core/ios/Swift/DynamicTypes/DynamicEnumType.swift:7:22: error: expected declaration
let innerType: any Enumerable.Type
Unfortunately, we don't have the chat app example for Expo. Errors you've provided aren't related to ConnectyCube's services.
You can make chat app using our ConnectyCube SDK. The SDK supports Expo except WebRTC (video/audio calls).
See docs how to use ConnectyCube's API and chat for React Native here
Try simple code how to use ConnectyCube SDK with Expo:
npx create-expo-app ExpoConnectyCube
cd ExpoConnectyCube
yarn add react-native-connectycube
yarn ios
import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import ConnectyCube from "react-native-connectycube";
const creds = {
appId: 385,
authKey: "DFBMs5-dKBBCXcd",
authSecret: "SkCW-ThdnmRg9Za",
};
const conf = {
debug: { mode: 1 },
};
const user = {
id: 72780,
login: "videouser1",
password: "videouser1",
};
export default function App() {
const [session, setSession] = useState("empty");
const [chat, setChat] = useState(false);
const [message, setMessage] = useState("");
const initConnectyCube = () => {
ConnectyCube.init(creds, conf);
};
const createAuthSession = () => {
ConnectyCube.createSession({ login: user.login, password: user.password })
.then((result) => {
setSession(result);
})
.catch((sessionError) => setChat(sessionError));
};
const chatConnect = () => {
ConnectyCube.chat.onMessageListener = (user, message) => {
setMessage({ user, message });
};
ConnectyCube.chat
.connect({ userId: user.id, password: user.password })
.then(() => {
setChat(true);
ConnectyCube.chat.send(user.id, { body: "Hello", type: "chat" });
})
.catch((chatError) => setChat(chatError));
};
useEffect(() => {
initConnectyCube();
createAuthSession();
chatConnect();
}, []);
return (
<View style={styles.container}>
<Text>{`Session: ${JSON.stringify(session)} \n`}</Text>
<Text>{`Chat connected: ${chat} \n`}</Text>
<Text>{`onMessage: ${JSON.stringify(message)} \n`}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
justifyContent: "center",
},
});

Uhandled atob variable on screen rendering

The error I get is [Unhandled promise rejection: ReferenceError: Can't find variable: atob].
And my screen code:
import React, { Component } from "react";
import { View, StatusBar, Text } from "react-native";
import firebase from "firebase";
import "firebase/firestore";
import { RowItem } from "../components/RowItem";
import { Header, Left, Right, Icon } from "native-base";
const styles = {
container: {
flexDirection: "row",
flexWrap: "wrap",
padding: 20
}
};
class QuizIndex extends Component {
constructor(props) {
super(props);
this.state = {
docs: []
};
}
async componentDidMount() {
await this.quizes();
}
quizes = async () => {
let result = await firebase
.firestore()
.collection("quiz")
.where("parentId", "==", "")
.get()
.then(r => {
console.log("fine");
})
.catch(e => {
console.log("Not fine");
});
const docs = result.docs.map(doc => {
return { uid: doc.id, ...doc.data() };
});
return this.setState({ docs });
};
render() {
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content" />
{this.state.docs.map(doc => (
<RowItem
key={doc.uid}
parentId={doc.parentId}
name={doc.title}
color={doc.color}
icon={doc.icon}
onPress={() =>
this.props.navigation.navigate("QuizSub", {
title: doc.title,
color: doc.color,
parentId: doc.uid
})
}
/>
))}
</View>
);
}
}
export default QuizIndex;
I don't get it where this problem occur because the things were working fine. Do you have any suggestion about this ? I googled it but none of the solutions helped me.
It's an issue in firebase dependency
Try to use version 7.9.0, this version will work fine.
yarn add firebase#7.9.0
I think if you install the base-64 npm package it will solve, but don't quite know why this is happening.
yarn add base-64
#or
npm install base-64
At App.js add:
import {decode, encode} from 'base-64'
if (!global.btoa) { global.btoa = encode }
if (!global.atob) { global.atob = decode }

React Native Expo “AppLoading threw an unexpected error when loading” error

I have a React Native project with Expo, I installed Expo client on my Android phone. It used to work well so far. But even though I didn't change any code, I now get the following error when I scan the QR code from my phone. This error is shown on terminal and phone screen keeps blank.
import React from 'react';
import { Image } from 'react-native';
import { AppLoading } from 'expo';
import { Asset } from 'expo-asset';
import { Block, GalioProvider } from 'galio-framework';
import Screens from './navigation/Screens';
import { Images, articles, ditsTheme } from './constants';
// cache app images
const assetImages = [
Images.Onboarding,
Images.LogoOnboarding,
Images.Logo,
Images.Pro,
Images.DITSLogo,
Images.iOSLogo,
Images.androidLogo
];
// cache product images
articles.map(article => assetImages.push(article.image));
function cacheImages(images) {
return images.map(image => {
if (typeof image === 'string') {
return Image.prefetch(image);
} else {
return Asset.fromModule(image).downloadAsync();
}
});
}
export default class App extends React.Component {
state = {
isLoadingComplete: false,
}
render() {
if(!this.state.isLoadingComplete) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
} else {
return (
<GalioProvider theme={ditsTheme}>
<Block flex>
<Screens />
</Block>
</GalioProvider>
);
}
}
_loadResourcesAsync = async () => {
return Promise.all([
...cacheImages(assetImages),
]);
};
_handleLoadingError = error => {
// In this case, you might want to report the error to your error
// reporting service, for example Sentry
warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
How can I solve this error?
In your _handleLoadingError method, you're using warn. While you should be using console.warn. This is what's breaking your app.
I was getting this error, the problem was with AppLoading. The issue turned out to be incorrect function name that I was calling from <AppLoading .. />
Note below, I was using Font.loadAsync (with missing c), fixing it made the font load correctly.
const getFonts = () => Font.loadAsyn({
'nanitu-regular' : require('./assets/fonts/EastSeaDokdo-Regular.ttf'),
'nanitu-bold' : require('./assets/fonts/NanumBrushScript-Regular.ttf')
})
;
You should add onError to AppLoading. As a like:
<AppLoading startAsync={getFonts} onFinish={() => {
setFontLoaded(true)
}} onError={console.warn} />

expo-av bare Error: Missing audio recording permissions

Was looking to use the recently available expo packages for detached or "bare" apps in react-native.
Running into the following error:
Error: Missing audio recording permissions.
however I have already called the expo-permissions library to ensure RecordAudio permissions are obtained.
See https://github.com/Glorifundel/bareaudio for full example project
App.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, Button } from 'react-native';
import * as Permissions from 'expo-permissions';
import { Audio } from 'expo-av';
export default class App extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Button title="Get Permission" onPress={this.onPressPermission} />
<Button title="Record" onPress={this.onPressRecord} />
</View>
);
}
onPressPermission = async () => {
const { status, expires, permissions } = await Permissions.askAsync(
Permissions.CAMERA_ROLL,
Permissions.AUDIO_RECORDING
);
alert(`permission: ${status}`);
};
onPressRecord = async () => {
const recording = new Audio.Recording();
try {
await recording.prepareToRecordAsync(
Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY
);
await recording.startAsync();
alert(`onPressRecord recording!`);
} catch (error) {
alert(`onPressRecord error: ${error}`);
}
};
}
Pressing the "Get Permission" button reports an alert "permissions: granted", following that up with pressing the "Record" button results in an alert "onPressRecord error: Error: Missing audio recording permissions."
Any insight is appreciated,
Environment details: I am running on windows 10, on an android emulator running android API 27 (8.1 Oreo). Did a fresh Node v10.15.3 install as well as a fresh react-native-cli expo-cli install and generated the project with expo init --template bare-minimum. followed up with yarn add expo-av and yarn add expo-permissions, followed the instructions found on the readme for the two packages.
async function startRecording() {
try {
console.log('Requesting permissions..');
await Audio.requestPermissionsAsync().then(() => {
console.log('Permission granted!');
})
.catch(error => {
console.log(error);
});
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
});
console.log('Starting recording..');
const { recording } = await Audio.Recording.createAsync(
Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY
);
setRecording(recording);
console.log('Recording started');
} catch (err) {
console.error('Failed to start recording', err);
}
}

Invariant Violation: Unable to find node on an unmounted component. Apollo

I have some problems testing a Component inside a Create React App that returns a Query Component, I'm using jest and enzyme for testing. The error that I get is Invariant Violation: Unable to find node on an unmounted component.. Any ideas with what I'm doing wrong? What I'm trying to get is to test that the query component will return an array of components based on the data received from the server.
I tried using the methods posted in this medium article, but I can't get it to work at all.
// The component
export class MyWrapper extends React.Component {
render() {
return (
<List divided verticalAlign="middle" >
<Query query={query} >
{({ data, loading, error, refetch }) => {
if (loading) return <Loader />;
if (error) return <ErrorMessage />;
// set refetch as a class property
this.refetch = refetch;
return data.response
.map(el => (
<MyComponent
el={el}
/>
));
}}
</Query>
</List>
);
}
}
export default compose(
...//
)(MyWrapper);
// The test file
import React from "react";
import { MockedProvider } from "react-apollo/test-utils";
import query from "path/to/query";
import { MyWrapper } from "../MyWrapper";
import { props } from "./props";
const mocks = {
request: {
query,
},
result: {
data: {
response: [
// data
]
}
}
};
describe("<MyWrapper />", () => {
describe("rendering", () => {
it("renders <MyComponent />'s", async () => {
const wrapper = mount(
<MockedProvider mocks={mocks} removeTypename>
<MyWrapper {...props} />
</MockedProvider>
);
await new Promise(resolve => setTimeout(() => resolve(), 1000));
wrapper.update();
console.log(wrapper.debug());
});
});
});
This is the code snippet I tried to reproduce:
const wait = require('waait');
it('should render dog', async () => {
const dogMock = {
request: {
query: GET_DOG_QUERY,
variables: { name: 'Buck' },
},
result: {
data: { dog: { id: 1, name: 'Buck', breed: 'poodle' } },
},
};
const component = renderer.create(
<MockedProvider mocks={[dogMock]} addTypename={false}>
<Dog name="Buck" />
</MockedProvider>,
);
await wait(0); // wait for response
const p = component.root.findByType('p');
expect(p.children).toContain('Buck is a poodle');
});
After Googling to solve this for myself I found this.
According to this Git Issue the problem is in enzyme-adapter-react-16. EthanJStark said that updating to enzyme version 1.5.0 corrected it. I can confirm that the error stopped.
tldr;package.json – "enzyme-adapter-react-16": "^1.1",
+ "enzyme-adapter-react-16": "^1.5.0",
I was getting Invariant Violation: Unable to find node on an unmounted component too with TypeScript and Next.js in the mix.
After creating an isolated project which worked, I knew it had to be my codebase.
The stack trace seemed to stem at invariant (node_modules/react-dom/cjs/react-dom.development.js:55:15).
So in my case, upgrading from "react-dom": "16.5.2" to "react-dom": "16.7.0" fixed the issue for me, along with re-creating my yarn.lock file.