I've started learning React Native with Redux and I'm building a simple login with Google and Facebook login which I want to sent to a Parse backend on AWS.
I have the following Facebook Button Component:
import { Button } from 'react-native';
import { connect } from 'react-redux';
import React, { Component } from 'react';
import { LoginManager } from 'react-native-fbsdk';
import { createUser } from '../actions';
class FacebookButton extends Component {
facebookButtonPressed(){
this.props.createUser("dummyemail#gmail.com","12345");
}
render() {
return (
<Button
onPress={this.facebookButtonPressed.bind(this)}
title="Sign In with Facebook"
color="#000000"
/>
);
}
}
export default connect(null,{ createUser })(FacebookButton);
I haven't done any Facebook integration yet, I just want to see if I can create a parse user. This is the action I'm using:
import Parse from 'parse/react-native';
export const createUser = (email, name) => {
return (dispatch) => {
var user = new Parse.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("name",name);
user.set("email", email);
// other fields can be set just like with Parse.Object
user.set("phone", "415-392-0202");
user.signUp(null, {
success: function(user) {
// Hooray! Let them use the app now.
console.log("User created");
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}
});
}
};
When I run the debugger in the browser, I'm able to see that the createUser is called and when we call user.signUp I get the following error:
undefined is not an object (evaluating 'reactNative.AsyncStorage.getItem')
When I read the Parse Javascript docs and try the following:
//Get your favorite AsyncStorage handler with import (ES6) or require
import { AsyncStorage } from 'react-native';
//Before using the SDK...
Parse.setAsyncStorage(AsyncStorage);
I call the Parse.setAsyncStorage(AsyncStorage); in the code below.
import ReduxThunk from 'redux-thunk';
import reducers from './src/reducers';
import Parse from 'parse/react-native';
import { Provider } from 'react-redux';
import Login from './src/screens/Login';
import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import { createStore, applyMiddleware } from 'redux';
export default class App extends Component {
componentWillMount() {
Parse.initialize("MY KEY");
Parse.serverURL = 'MY URL';
Parse.setAsyncStorage(AsyncStorage);
}
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Login />
</Provider>
);
}
}
I get an error of reactNative2.default.setAsyncStorage is not a function. Frankly I tried Parse.setAsyncStorage(AsyncStorage); in hopes of this fixing the AsyncStorage issue mentioned above.
So any ideas as to why I get the funny AsyncStorage error message when trying to create a Parse user?
I'm leaving an answer here in case someone else stumbles across any other issues. The problem was the version of Parse I was using. I was using Parse version 1.6.14. Steps to fix:
Open the package.json file and update your Parse version to any version above 1.11, for me 1.11.1 worked.
In the terminal: npm install
this should fix the issues mentioned above, bear in mind that you have to implement:
//Get your favorite AsyncStorage handler with import (ES6) or require
import { AsyncStorage } from 'react-native';
//Before using the SDK...
Parse.setAsyncStorage(AsyncStorage);
as per documentation.
Related
In react native app , I am using firebase google analytics.
The problem is in tracking screens, I follow this link , however I am having
this error .
TypeError: (0 , _analytics.analytics) is not a function).
And the Screenshoot.
My appcontainer file (drawer.js) :
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createAppContainer } from 'react-navigation';
import Feed from '../components/Home';
import {FeedStack} from './stack';
import React, { Component } from 'react';
import {analytics }from '#react-native-firebase/analytics';
const MyDrawerNavigator = createDrawerNavigator(
{
Feed: FeedStack
},
);
function getActiveRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
}
const AppContainer =createAppContainer(MyDrawerNavigator);
export default () => {
return <AppContainer
onNavigationStateChange={(prevState, currentState, action) => {
const currentRouteName = getActiveRouteName(currentState);
const previousRouteName = getActiveRouteName(prevState);
if (previousRouteName !== currentRouteName) {
analytics().setCurrentScreen(currentRouteName, currentRouteName);
}
}}
/>
}
My app.js :
import Feed from './src/components/Home';
import HomePage from './src/components/homeEpaper';
import Navigator from './src/navigator/drawer';
import React, { Component } from 'react';
export default function App() {
return (
<Navigator />
)
}
I tried also import analytics from '#react-native-firebase/analytics';
and i got this error. screenshot
if you're using setCurrentScreen method, then you need to use the following
package.jsom
"#react-native-firebase/analytics": "^10.4.0",
"#react-native-firebase/app": "^10.4.0",
Incorrect
import analytics from '#react-native-firebase/analytics';
.
.
.
analytics().setCurrentScreen('SignUpScreen');`
Correct
import analytics from '#react-native-firebase/analytics';
.
.
.
// Google Firebase Analytics
analytics().logScreenView({
screen_name: 'SignUpScreen',
screen_class: 'SignUpScreen'
});
I think that you didn't follow the docs 100% to the point :)
In your code you do:
import {analytics }from '#react-native-firebase/analytics';
However if you look at this file: https://github.com/invertase/react-native-firebase/blob/master/packages/analytics/lib/index.js you'll see that there is no named export analytics. What you do when you type import {analytics} is importing a named export: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
Since there is no named export analytics in that file the value for analytics is undefined and you get the error you describe.
I should type (as written in the linked example):
import analytics from '#react-native-firebase/analytics';
In new update setCurrentScreen is no longer present. Use other functions to log.
Version:
#react-native-community/async-storage = ^1.6.1
Problem:
Importing AsyncStorage like this:
import { AsyncStorage } from '#react-native-community/async-storage'
Using in my code like this:
AsyncStorage.setItem('locale', locale)
AsyncStorage.getItem('user').then((value) =>
{
...
}
Errors:
TypeError: undefined is not an object (evaluating
'_asyncStorage.AsyncStorage.setItem')
TypeError: undefined is not an object (evaluating '_asyncStorage.AsyncStorage.getItem')
What I've tried
Importing AsyncStorage from 'react-native' gives no problems, only warning that AsyncStorage should be imported from '#react-native-community' because the AsyncStorage from 'react-native' is deprecated.
Tried to uninstall and reinstall '#react-native-community/async-storage'-dependency, that didn't work.
Googling it
Full code:
import React from 'react';
import { View, Image, NativeModules } from 'react-native';
import { AsyncStorage } from '#react-native-community/async-storage'
import { styles } from '../../components/Styles.js';
import { GEOLocation } from '../../scripts/GEOLocation';
import Moment from 'moment/min/moment-with-locales';
export default class SplashScreen extends React.Component {
constructor(props) {
super(props);
this.geo = new GEOLocation();
this.setLocale();
this.bootstrapAsync();
}
bootstrapAsync = async () => {
this.geo.grantAccess()
AsyncStorage.getItem('user').then((value) => {
const user = JSON.parse(value);
this.props.navigation.navigate(user ? 'App' : 'Auth');
})
};
setLocale = () => {
const deviceLocale = NativeModules.I18nManager.localeIdentifier
var locale;
if (deviceLocale.includes('_')) {
var language = deviceLocale.split('_')[0]
var country = deviceLocale.split('_')[1].toLowerCase()
locale = language + '-' + country
} else {
locale = deviceLocale
}
if(Moment.locales().indexOf(locale) > -1 ) {
console.log('device locale')
AsyncStorage.setItem('locale', locale)
} else {
console.log('default locale')
AsyncStorage.setItem('locale', 'en')
}
}
render() {
return (
<View style={styles.container}>
<Image style={styles.leImage} source={require('../../../assets/logo_icon.png')} />
</View>
)
}
}
Here's how to use the correct method for importing.
import AsyncStorage from '#react-native-community/async-storage';
This module is not exported as a react-native, so it must not have a square bracket.
Use in react-native module
import { AsyncStorage } from 'react-native';
#react-native-community/async-storage is now deprecated
Use react-native-async-storage/async-storage
instead.
Note: It does not use brackets. Unlike before when it was one of many things exported from react-native, it is now the default export of #react-native-async-storage/async-storage.
import AsyncStorage from '#react-native-async-storage/async-storage';
Yes my issue resolved by using below
import AsyncStorage from '#react-native-async-storage/async-storage';
before this I was using parentheses and getting error.
import { Sound } from 'react-native-sound'
import React, { Component } from 'react'
import { Button } from 'react-native'
//import Audio from 'react-native-audio'
class About extends Component {
playTrack = () => {
const track = new Sound('geetha_govindham_song.mp3','', null, (e) => {
if (e) {
console.log('error loading track:', e)
} else {
//track.play()
}
})
track.play()
}
render() {
console.log("CCCCC", JSON.stringify(Sound));
return <Button title="play me" onPress={this.playTrack} />
}
}
export default About
After executing this we got the error like undefined is not a constructor.
Here, i used react-native-sound module for playing mp3 song. But, I got the error like, what shown in the picture. Please give any suggestion to me to solve the issue.
Could you try using require?
const Sound = require('react-native-sound');
you should do default import:
import Sound from ‘react-native-sound’
You can find the example in the project’s README: https://github.com/zmxv/react-native-sound/blob/master/README.md
I'm trying to test if my generator function is called when I call dispatch function. I'm doing something like:
in my saga.js:
import { takeLatest } from 'redux-saga/effects'
import { SIGNIN_FORM_SUBMIT } from './constants'
export default function* signInFormSubmit() {
return yield takeLatest([SIGNIN_FORM_SUBMIT], function*() {
console.log("I'm in")
return yield null
})
}
in Form.js:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { SIGNIN_FORM_SUBMIT } from '../constants'
class SignInForm extends Component {
handleSubmit = this.handleSubmit.bind(this)
handleSubmit() {
this.props.dispatch({
type: SIGNIN_FORM_SUBMIT
})
}
render() {
return (
<div>
<button onClick={() => this.handleSubmit()}>Submit</button>
</div>
)
}
}
export default connect()(SignInForm)
in my test.js:
import React from 'react'
import configureStore from 'redux-mock-store'
import createSagaMiddleware from 'redux-saga'
import { Provider } from 'react-redux'
import { mount } from 'enzyme'
import signInFormSubmitSaga from '../saga'
import SignInForm from '../components/Form'
const sagaMiddleware = createSagaMiddleware()
const mockStore = configureStore([sagaMiddleware])
const store = mockStore()
sagaMiddleware.run(signInFormSubmitSaga)
describe('<Form />', () => {
test('should call signInFormSubmit saga when I click on the sumbit button', () => {
const wrapper = mount(
<Provider store={store}>
<SignInForm />
</Provider>
)
wrapper.find('button')
.simulate('click')
// I'm blocked here
// expect(...).toHaveBeenCalledTimes(1)
}
})
I think my problem is that I have to mock the generator function that I pass as params to takeLatest. I tried lot of things but it didn't work.
The result show well "I'm in"
Thanks guys for your help :)
check out this link to see example test of a saga: https://github.com/react-boilerplate/react-boilerplate/blob/master/app/containers/HomePage/tests/saga.test.js
What you want to do is test the saga generator function, in your case the signInFormSubmit...
You would import it as such as:
signInFormSubmitGenerator = signInFormSubmit();
Then you would want to assert things against the values returned at each 'yield' step.
However, I noticed that you have takeLatest within your generator function, which I don't believe is correct way to use it, its used to trigger other sagas (so it should be outside of the function, take a look here for example of well structured saga: https://github.com/react-boilerplate/react-boilerplate/blob/master/app/containers/HomePage/saga.js, notice how takeLatest is all the way at the bottom, and used as an entry point or a trigger for the generator function above it)
I have delete_task action that POST the task id to PHP file to delete the task , although the action I fired correctly and i see the effect in the console but the task not deleted, i tried many many times using GET OR POST OR JUST put the id statically in the URL but nothing changing,can anyone help me to solve the problem
tasksAction.js
export const delete_task = id => ({
type: DELETE_TASK,
payload: {id},
meta: {
offline: {
// the network action to execute:
effect: { url: 'http://localhost/todos/remove.php', method: 'POST',body: {id} },
// action to dispatch when effect succeeds:
commit: { type: DELETE_SUCCESS, meta: { id } },
// action to dispatch if network action fails permanently:
rollback: { type: DELETE_FAILED, meta: { id } }
}
}
});
store.js
import React, { Component } from 'react';
import { applyMiddleware, createStore, compose } from 'redux';
import { offline } from '#redux-offline/redux-offline';
import offlineConfig from '#redux-offline/redux-offline/lib/defaults';
import {Provider} from 'react-redux';
import logger from 'redux-logger';
import RootNavigator from "./config/routes";
import reducers from './reducers'
// store
const middleware = [];
if(process.env.NODE_ENV === 'development'){
middleware.push(logger);
}
const store = createStore(
reducers,
undefined,
compose(
applyMiddleware(...middleware),
offline(offlineConfig)
)
);
export default class App extends Component {
render() {
return (
<Provider store={store}>
<RootNavigator />
</Provider>
)
}
}
In the offline object inside prev state, does it say online: false?
If it does, and you're developing in an Android emulator, Wifi is not available on the emulator if you are using below API level 25, so redux-offline thinks you have no connection and will not make the initial network request.
This occurred to me after testing redux-offline in an iOS simulator and everything worked.
Hope this helps.