React native: how to load AppRegistry component due to AsyncStorage - react-native

I want to load AppRegistry component due to AsyncStorage
this is the code in index.js:
import { AppRegistry } from 'react-native';
import { AsyncStorage } from 'react-native';
import index from './src/pages/LoginPage';
import HomeScreenRouter from './src/pages/CategoriesPage/index';
let page;
AsyncStorage.getItem("#token").then((value) => {
const token = value;
if(value === null) {
page = index;
} else {
page = HomeScreenRouter;
}
})
.then(res => {
});
AppRegistry.registerComponent('fatima2', () => page );
but I have an error that the app . doesn't found the AppRegistry component,
what should i do to solve this problem?

Corret usage of AsyncStorge is like that:
AsyncStorage.getItem('item', (err,result) => {
//Do your logic here
})
i dont know the main problem is this but, your usage may cause some issues.

Register a StactNavigator
in your AppRegistry. Add a new dummy page with empty view at the top of the navigator. So, when the app is opened the "DummyPage" will be displayed. At this stage, the StackNavigator will contain three pages i.e "DummyPage", "Index" and "HomeScreenRouter". Then read the value from Async Storage and on it's callback Reset your navigation stack
.
Then your StackNavigator will contain either "Index" or "HomeScreenRouter" screen.

Related

global.__reanimatedWorkletInit is not a function. react-native-animated v2

I using 'worklet'; and runOnUI() and then get the error below.
Because I use 'worklet'; I added import 'react-native-reanimated'
Because I also use runOnUI I added import {runOnUI} from 'react-native-animated'
Error:
ERROR TypeError: global.__reanimatedWorkletInit is not a function. (In 'global.__reanimatedWorkletInit(_f)', 'global.__reanimatedWorkletInit' is undefined)
ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
Short answer:
Besides runOnUI also import and use something else from react-native-reanimated, for example also add useSharedValue:
import { useSharedValue, runOnUI } from 'react-native-reanimated';
and use the shared value:
const sharedVal = useSharedValue(0);
Now the error will go away.
Long answer (how I got to the solution):
At first I got the error (global.__reanimatedWorkletInit is not a function.) when trying to create a widget:
import React from 'react';
import { Text } from 'react-native';
const Example = () => {
const someWorklet = () => {
'worklet';
console.log("Hey I'm running on the UI thread");
};
return (<Text>Example</Text>);
};
export default Example;
Adding import 'react-native-reanimated'; helped me to get rid of the error.
Then I wanted to run someWorklet. So I added a runOnJS (runOnUI got me the same results) call. My component now returned:
<View>
<Text>Worklet: {runOnUI(someWorklet)()}</Text>
</View>
and I imported it via import { runOnUI } from 'react-native-reanimated';.
Now the same error was back.
Only after I also imported and called useSharedValue everything worked as expected. This is my component code which didn't throw the error anymore:
import React from 'react';
import { View, Text } from 'react-native';
import { useSharedValue, runOnJS } from 'react-native-reanimated';
const Example = () => {
const someWorklet = () => {
'worklet';
console.log("Hey I'm running on the UI thread");
return 'World';
};
const sharedVal = useSharedValue(0);
return (
<View>
<Text>Hello, {runOnJS(someWorklet)()}</Text>
</View>
);
};
export default Example;
Just add these two lines in App.tsx and index.js
1)import "react-native-reanimated"
2)global.__reanimatedWorkletInit = () => {}

compiled application not loading in real device

For the life of me, I can't figure it out. All it shows is spinning without end and i am confused on the order of the life cycle happening. Basically, it goes to login or home screen and it works correctly on emulator but not on real device. I am on react 16.8.6 and react-native 0.60.5 environment.
I am getting started with RN and my debugging tools are not great. But for now just used Alert to see and the logic that was supposed to redirect to login/home screen is never reached. The Alerts shown are in the following order:
BS
mount2
render
mount1
My code is below: if the token exists, load home screen. else load auth screen is what I wanted to achieve but for now the line:
this.props.navigation.navigate(!goToLogin ? 'App' : 'Auth');
is never reached and so, spins a lot. Any help?
import React, {Component} from 'react';
import {StatusBar, View, Alert} from 'react-native';
import {
getUserToken,
loggedInToAssociation,
extractToken,
} from '../shared/loggedinUser';
import {setLanguage} from '../shared/localization';
import {appOptions} from '../config';
import Spinner from '../components/Spinner';
export default class AuthLoadingScreen extends Component {
constructor() {
super();
this.state = {
languageLoaded: false
};
}
componentDidMount() {
Alert.alert("mount1","oumnt1") // shown
loggedInToAssociation()
.then(details => {
// details is an array now
setLanguage(details['language']);
this.setState({languageLoaded: true});
Alert.alert("mount2","oumnt2") // SHOWN
})
.catch(err => {
setLanguage(appOptions.defaultLanguage);
this.setState({languageLoaded: true});
Alert.alert("mount3","oumnt3")
});
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await getUserToken();
Alert.alert("bs","bs") // SHOWN
const tokenInfo = extractToken(userToken, 'both');
let goToLogin = true; // force user to go to the login page
if (tokenInfo.length == 2) {
goToLogin = false;
}
Alert.alert("bs2","bs2") // NEVER SHOWN
this.props.navigation.navigate(!goToLogin ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
if (this.state.languageLoaded){
this._bootstrapAsync().then(s=>{
console.log(s)
}).catch(e=>{
console.log(e)
})
}
return (
<View>
<Spinner />
<StatusBar barStyle="default" />
</View>
);
}
}
did you check your debug console when running on device? There might be an unhandled promise rejection. The promise didn't go through but nowhere to handle the catch (consider try-catch scenario for this context).
It might be having a problem with this method.
extractToken(userToken, 'both')

React native RNFS library

I have used react native RNFS library to access my mobile's file system . I am able to delete the file using file name. For example,
import React, { Component } from "react";
import { Text, View } from "react-native";
var RNFS = require("react-native-fs");
var path = RNFS.ExternalDirectoryPath + "/abc.png";
export default class HelloWorldApp extends Component {
render() {
return (
RNFS.unlink(path)
.then(() => {
console.log("FILE DELETED");
console.log(path);
})
.catch(err => {
console.log(err.message);
console.log(path);
})
);
}
}
Here, file with name abc.png will get deleted.
Question 1 - But suppose if want all files with a particular extension (like .txt,.png) to get deleted, then how can i achieve that ??
Question 2- using this code, Although I am able to delete the file but i am getting error in console .
Invariant Violation: Objects are not valid as a React child (found:
object with keys {_40, _65, _55, _72}). If you meant to render a
collection of children, use an array instead.
in HelloWorldApp (at renderApplication.js:34)
in RCTView (at View.js:45)
in View (at AppContainer.js:98)
in RCTView (at View.js:45)
in View (at AppContainer.js:115)
in AppContainer (at renderApplication.js:33)
I have used this documentation for writing code - https://github.com/itinance/react-native-fs
Delete files of a specific extension
It is possible to delete files with a specific extension it is a little involved but it is not too complicated. There are a few steps that we need to accomplish to make it happen.
Get a list of all the files in the directory
Filter the list so that only the files with the extension that we want to delete are left.
Unlink the files that are in our list.
So we could do something like this:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Button} from 'react-native';
const RNFS = require('react-native-fs');
export default class App extends Component<Props> {
deleteFiles = async () => {
let ext = 'txt'; // extention that we want to delete
var re = /(?:\.([^.]+))?$/; // regex to get the file extension of the file
try {
let path = RNFS.DocumentDirectoryPath;
let fileList = await RNFS.readDir(path); // get all the files in the directory
if (fileList.length) {
let filesToDelete = fileList.filter(file => {
let extension = re.exec(file.name)[1] // gets the extension of the found file
return extension === ext; // check to make sure that each file has the extension that we are looking for
});
for (const file of filesToDelete) {
if (file.isFile()) { // only delete if it is a file
try {
await RNFS.unlink(file.path);
console.log(`Successfully deleted ${file.name}`);
} catch (deleteError) {
console.log(`Error deleting ${file.name}`);
}
}
}
}
} catch (err) {
console.warn(err);
}
}
render() {
return (
<View style={styles.container}>
<Button title={'delete files'} onPress={this.deleteFiles} />
</View>
);
}
}
This is a simple component that renders a button on screen. The deleteFiles function is called when the button is pressed. Currently it is set up to delete all files with the extension txt
Error: Invariant Violation: Objects are not valid as a React child
You are calling the function inside the return of your render method. You shouldn't be doing that. Either implement something like I have above where the files are deleted on the press of a button or the function to delete is called via a specific action, if you need to delete the file when the component is created then you should be doing that inside the componentDidMount rather than in the render function.
componentDidMount () {
RNFS.unlink(path)
.then(() => {
console.log("FILE DELETED");
console.log(path);
})
.catch(err => {
console.log(err.message);
console.log(path);
});
}
You can use readdir to get the file names and then pass the ones you want to delete to unlink
This error is because you are not returning a component. The render() method expects a react component as its return value.
When you return something from render(){} it need to beJSX, you cant render RNFS, because it's not JSX.
return (
RNFS.unlink(path)
.then(() => {
console.log("FILE DELETED");
console.log(path);
})
.catch(err => {
console.log(err.message);
console.log(path);
})
);
I'm not sure what you want to render, but that is why you are getting this error.
Objects are not valid as a React child means "you can't render an Object", to render something, it need to be a JSX
(e.g <Text>hey<Text>)

Changing state in React native App.js from another component

I'm making authentication in an app, and I'm kind of stuck. I have 2 different navigations. One shows if the user is logged in and another one if not. Basically, a Sign in screen. It's working fine if I change the value manually upon the start. But I can't find a way to change a state when a user signs in, for example. Even though the value in auth module changes, it doesn't update in App.js So how can I update the App.js's state from Sign in screen, for example?
import React, { Component } from 'react';
import { AppRegistry, Platform, StyleSheet, Text, View } from 'react-native';
import DrawerNavigator from './components/DrawerNavigator'
import SignedOutNavigator from './components/SignedOutNavigator'
import auth from './auth'
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props)
this.state = {
isLoggedIn: auth.isLoggedIn
}
}
render() {
return (
(this.state.isLoggedIn) ? <DrawerNavigator /> : <SignedOutNavigator />
);
}
}
AppRegistry.registerComponent('App', () => App)
and my auth module, which is very simple
import { AsyncStorage } from 'react-native';
// try to read from a local file
let api_key
let isLoggedIn = false
function save_user_settings(settings) {
AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
AsyncStorage.getItem('user', (err, result) => {
isLoggedIn = result.isLoggedIn
api_key = result.api_key
});
isLoggedIn = true
});
}
module.exports.save_user_settings = save_user_settings
module.exports.api_key = api_key
module.exports.isLoggedIn = isLoggedIn
First off, there are loads of ways to approach this problem. Because of this I'm going to try explain to you why what you have now isn't working.
The reason this is happening is because when you assign auth.isLoggedIn to your isLoggedIn state, you are assigning the value once, kind of as a copy. It's not a reference that is stored.
In addition to this, remember, React state is generally only updated with setState(), and that is never being called here, so your state will not update.
The way I would approach this problem without bringing in elements like Redux, which is overkill for this problem by itself, is to look into building an authentication higher order component which handles all the authentication logic and wraps your entire application. From there you can control if you should render the children, or do a redirect.
Auth Component
componentDidMount() {
this._saveUserSettings(settings);
}
_saveUserSettings(settings) {
AsyncStorage.mergeItem('user', JSON.stringify(settings), () => {
AsyncStorage.getItem('user', (err, result) => {
isLoggedIn = result.isLoggedIn
api_key = result.api_key
});
this.setState({isLoggedIn: true});
});
}
render() {
const { isLoggedIn } = this.state;
return isLoggedIn ? this.props.children : null;
}
App.js
render() {
<AuthComponent>
//the rest of authenticated app goes here
</AuthComponent>
}
Here's a really quick, incomplete example. But it should showcase to you how you may want to lay your authentication out. You'll also want to consider error handling and such, however.

How to set config show/hide refresh button on AppBar

Click to see image
Button refresh on AppBar is not refresh on page Dashboard because I just use Component Card but work on page using component List or Datagrid, so I want to config show/hide refresh button on AppBar or how to fix it work for page not use component List or Datagrid.
Sorry I'm not strong in English.
You'll have to fetch some data from the react-admin state for it to work. Indeed, the refresh button just trigger the refreshView action which update the state.admin.ui.viewVersion key of the the react-admin redux state. This key is a simple counter. Internally, we use this counter to check whether we must update some components data. Here is a simple example of a connected Dashboard which can do things when refreshed:
import React, { Component } from "react";
import { connect } from "react-redux";
class Dashboard extends Component {
componentDidMount() {
this.doOnMountAndWhenRefreshed();
}
componentDidUpdate(prevProps) {
if (prevProps.views !== this.props.views) {
this.doOnMountAndWhenRefreshed();
}
}
doOnMountAndWhenRefreshed = () => {
// This is where you do update your component:
// - Make API requests
// - Fetch data from the react-admin store, etc.
};
render() {
const { views } = this.props;
return <div>Refreshed {views} times.</div>;
}
}
const mapStateToProps = state => ({ views: state.admin.ui.viewVersion });
export default connect(
mapStateToProps,
{}
)(Dashboard);
You can see it working in this codesandbox
Edit for newer version of react-admin
import { useVersion } from 'react-admin';
const Dashboard = () => {
const version = useVersion();
return <div>Refreshed {version} times.</div>;
}
In react-admin 4.x I managed to get the desired behaviour like this:
import React from 'react'
import { useQuery } from 'react-query'
const noop = async () => new Date().valueOf()
export const MyDashboard = () => {
const { data } = useQuery('myDashboard', noop)
return (
<div>Last refreshed at {data}</div>
)
}
export default MyDashboard
Note how data represents the value returned by noop().
That way, whenever the user presses the refresh icon in the AppBar, the component is re-rendered.