How do I perform an onAuthStateChanged in Vue Native? - react-native

I want to perform something equivalent to this:
export default class LoadingScreen extends React.Component {
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
this.props.navigation.navigate(user ? 'App' : 'Auth');
});
}
render() {
return (
<View style={styles.container}>
<Text>Loading</Text>
<ActivityIndicator size='large'></ActivityIndicator>
</View>
);
}
}
I have setup my routes to go through the Loading to check the user's auth state before proceeding to either Auth or App. When I add mounted(), the loading text and activity-indicator don't show.
<template>
<view class="container">
<nb-text>Loading</nb-text>
<activity-indicator size="large" color="#0000ff" />
</view>
</template>
<script>
import firebase from "firebase";
import Fire from "./../../api/firebaseAPI";
export default {
// Declare `navigation` as a prop
props: {
navigation: {
type: Object,
},
},
async mounted() {
await firebase.auth().onAuthStateChanged(function (user) {
this.navigation.navigate(user ? "App" : "Auth");
});
},
};
</script>
When I run this code above I get a white screen.

Maybe we should move the code in mounted to a method.
<script>
mounted(){
this.checkAuth()
},
...
methods:{
async checkAuth(){
await firebase.auth().onAuthStateChanged(function (user) {
if(user){
this.navigation.navigate("Auth")
}else{
this.navigation.navigate("App")
}
});
}
}
</script>

Related

pass value from React Native picker component back to VueJS caller

I have the following React Native picker component that works -
file name: dynamic-picker.js
import React, { Component } from "react";
import { Container, Content, Picker } from "native-base";
export default class DynamicPicker extends Component {
constructor(props) {
super(props);
this.state = {
selected: this.props.selected
}
}
onValueChange(value) {
this.setState({
selected: value
});
}
itemsList = () => {
return (this.props.items.map( (item, index) => {
return (<Picker.Item label={item} key={index} value={item} />)
}));
}
render() {
return (
<Container>
<Content>
<Picker
mode="dropdown"
selectedValue={this.state.selected}
onValueChange={this.onValueChange.bind(this)}
>
{ this.itemsList() }
</Picker>
</Content>
</Container>
);
}
}
It is being called by a Vue JS file as follows -
file name: distance.vue
<template>
<dynamic-picker :items="items" :selected="selected" ></dynamic-picker>
</template>
<script>
import DynamicPicker from './dynamic-picker';
export default {
components: {
DynamicPicker
},
data() {
return {
selected: 'yards',
items: ["yards", "feet", "meters"]
}
}
}
</script>
The picker component is being displayed correctly. When the user selects a different option, that change is displayed in the picker component. However, I am stuck on how to get the selected property in the distance.vue file to update when the user selects a different option. That value needs to be captured so it can be passed on to the caller of the distance.vue file and used for a calculation.
Figured it out - added a callback to props so the child can call that function to pass data back to the parent when the value is changed.
Here is the updated distance.vue file (parent) -
<template>
<dynamic-picker :items="items" :selected="selected" :onValueChange="onValueChange" ></dynamic-picker>
</template>
<script>
import DynamicPicker from './dynamic-picker';
export default {
components: {
DynamicPicker
},
data() {
return {
selected: 'yards',
items: ["yards", "feet", "meters"]
}
},
methods: {
onValueChange(value) {
this.selected = value;
}
}
}
</script>
Then in dynamic-picker.js (child) the only change necessary was here -
onValueChange(value) {
this.setState({
selected: value
});
this.props.onValueChange(value); // added this line
}

ToastActionsCreators is not defined when using react-native-redux-toast

I am unable to call ToastActionsCreators when using react-native-redux-toast
I get a ToastActionsCreators is not defined error when I call this.props.dispatch(ToastActionsCreators.displayInfo("Info toast!", 2000)); in my screen component. Anyone knows how to resolve this?
In my react native debugger, I am able to see the toast reducer passed in by react-native-redux-toast. However, I have a problem calling the actions
Thank you
Here is sample of my code
In Redux Screen
class ReduxScreen extends Component {
_displayInfoToast = () => {
this.props.dispatch(ToastActionsCreators.displayInfo("Info toast!", 2000));
};
render() {
console.log(this.props);
const { counter } = this.props.test;
const { textStyle } = styles;
return (
<View>
<Text style={textStyle}>{counter.toString()} </Text>
<Button title="INCREMENT" onPress={this.props.incrementCounter} />
<Button title="DECREMENT" onPress={this.props.decrementCounter} />
<Button title="SHOW TOAST" onPress={this._displayInfoToast} />
</View>
);
}
}
const mapStateToProps = state => {
// console.log(state);
return {
test: state.test
};
};
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
incrementCounter,
decrementCounter
},
dispatch
);
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ReduxScreen);
In reducers/index.js
import { combineReducers } from "redux";
import testReducer from "./testReducer";
import { toastReducer as toast } from "react-native-redux-toast";
export default combineReducers({
// test: () => []
test: testReducer,
toast
});
I did not add any code to my actions file pertaining to react-native-redux-toast since its node needed
I am using react navigation createDrawerNavigator for navigation
App.js
class App extends Component {
constructor(props) {
super(props);
console.ignoredYellowBox = ["Setting a timer"];
}
render() {
return (
<ApolloProvider client={client}>
<Provider store={store}>
<MyProvider>
<Drawer />
<Toast messageStyle={{ color: "white" }} />
</MyProvider>
</Provider>
</ApolloProvider>
);
}
}
Full Code
https://github.com/myhendry/demo/tree/master/src/redux
You're not importing ToastActionCreators in ReduxScreen.js. That's why it's undefined; you haven't defined it anywhere in that file.
I finally managed to make it work! By doing below, it added in the dispatch function available in my props which allow me to call this.props.dispatch to dispatch the ToastActionCreators action creator to the store to show the toast.
Hope this will help others. Cheers
in my ReduxScreen.js, i added in the following...
import { Text, View, Button, StyleSheet } from "react-native";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { ToastActionsCreators } from "react-native-redux-toast";
import { incrementCounter, decrementCounter } from "./actions/index";
_displayInfoToast = () => {
this.props.dispatch(ToastActionsCreators.displayInfo("Info toast!", 2000));
};
const mapDispatchToProps = dispatch => {
return {
dispatch,
...bindActionCreators({ incrementCounter, decrementCounter }, dispatch)
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ReduxScreen);
I recommend using react-toastify package.
npm i --save react-toastify
// Simply import these two objects:
import { ToastContainer, toast } from 'react-toastify';
// Then make a toast function, something like this:
success = () => toast.info("Data successfully saved", { autoClose: 2000 });
// Somewhere in your code use your success toast function, like this:
saveNewUser = (data) => {
getUsers.addUser(data).then(res=> {
this.success(); // Here we trigger the that toast
}).catch(error => {
console.log('error while adding new user', error);
throw(error);
})
}
render() {
const {userData} = this.state;
return (
<div className="container">
// ...your logic goes here. This is just my example:
<table>
<thead>
<tr>
<th>Name</th>
<th>Date</th>
<th>Amount</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody>
{userData}
</tbody>
</table>
// Here we trigger our function that will also trigger our success toast :)
<button type="button"
onClick={this.saveNewUser}>
Save new user </button>
// Then just before the last closing </div> insert this
<ToastContainer autoClose={3000} closeOnClick />
</div>

React native show a strange behavior. Can someone explain?

I'am creating a simple application with authentication. To change a state using redux with react-native-navigation (v1). For example, index.js
...
import { Navigation, } from 'react-native-navigation';
import { Provider, } from 'react-redux';
import store from './src/store';
import registerScreens from './src/screens';
registerScreens(store, Provider);
class App {
constructor () {
this.auth = false;
store.subscribe(this.onStoreUpdate.bind(this));
this.start();
}
onStoreUpdate () {
const state = store.getState();
if (this.auth != state.auth) {
this.auth = state.auth;
this.start();
}
}
start () {
switch (this.auth) {
case false:
Navigation.startTabBasedApp({
tabs: [{
screen: 'navigation.AuthScreen',
}, {
screen: 'navigation.RegisterScreen',
},],
});
break;
case true:
Navigation.startSingleScreenApp({
screen: {
screen: 'navigation.MainScreen',
},
});
break;
}
}
}
const application = new App();
Store is listening an update and change an application layout if need.
AuthScreen show a simple ActivityIndicator, when server request is perform. For example, auth.js
...
import { bindActionCreators, } from 'redux';
import { connect, } from 'react-redux';
import * as actions from './../actions';
...
class AuthScreen extends Component {
constructor (props) {
super(props);
this.state = {
loading: false,
...
};
this.handlePressEnter = this.handlePressEnter.bind(this);
}
handlePressEnter () {
...
this.loadingState(true);
jsonFetch(url, {
method: 'POST',
body: JSON.stringify({...}),
}).then((value) => {
this.loadingState();
this.props.actions.auth(true);
}).catch((errors) => {
this.loadingState();
console.log('Error while auth', errors);
});
}
...
loadingState (state = false) {
this.setState({
loading: state,
});
}
render () {
return (<View>
...
<Modal visible={this.state.loading} transparent={true} animationType="none" onRequestClose={() => {}}>
<View>
<ActivityIndicator size="large" animating={this.state.loading} />
</View>
</Modal>
</View>);
}
}
function mapStateToProps (state, ownProps) {
return {};
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators(actions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps) (AuthScreen);
I'am starting application with iOS simulator and try to authenticate. It show me activity indicator, then indicator disappear, but layout does not change. And strange behavior, if I comment this.loadingState(true); and this.loadingState(); in auth.js layout changes with success.
Can someone explain to me, why layout does not change from auth to main when activity indicator using?
I think that you can use dispatch props for loading.
For example When you call this.props.actions.auth(true);
You can return loading reducers.
handlePressEnter () {
...
dispatch({ type:'loading', loading: true });
jsonFetch(url, {
method: 'POST',
body: JSON.stringify({...}),
}).then((value) => {
dispatch({ type:'loading', loading: false });
this.props.actions.auth(true);
}).catch((errors) => {
this.loadingState();
console.log('Error while auth', errors);
});
}
And than you can use
<ActivityIndicator size="large" animating={this.props.loading} />
But dont forget the reducers return

test with enzyme a react component with context: return an empty object

I'm trying to execute a dummy test with enzyme over a component. the test is about to check the context. even though I'm writing the same code as enzyme's documentation the context is always empty.
import React from 'react';
import { shallow } from 'enzyme';
import Overlay from '../../../../app/components/Overlay/Overlay';
describe('<Overlay />', () => {
it.only('return a context', () => {
const wrapper = shallow(<Overlay />, { context: { foo: 10 } });
console.log(wrapper.context());
// expect(wrapper.context().foo).to.equal(10);
});
})
the test's output is:
<Overlay />
{}
✓ return a context
where am I wrong?
Since the details of Overlay component is not given, I assume the context is not used in it (pls check childContextTypes and getChildContext are defined properly)
For example, refer the explanation for contexts in react documents
I have taken the same example to enable the test,
import React from 'react';
export default class Button extends React.Component {
render() {
return (
<button style={{ background: this.context.color }}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: React.PropTypes.string,
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
getChildContext() {
return { color: 'purple' };
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: React.PropTypes.string,
};
I've created the test for Button component as below,
import React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import Button from '../../src/components/SampleComp';
describe.only('<Button />', () => {
it('assert for context', () => {
const wrapper = shallow(
<Button />,
{ context: { color: 'red' } }
);
expect(wrapper.context().color).to.equal('red');
expect(wrapper.context('color')).to.equal('red');
});
});
<Button />
✓ assert for context
1 passing (214ms)
This will assert it correctly.

Implement FB login with react native and redux

I want to use Redux framework in my react native based app for implementing Facebook login (I am learning Redux at the moment). I am looking for suggestions on how to structure my Facebook login code to use the redux. More specifically, what actions, reducer and store should I create?
Below is the current Facebook based login code that I have in my app (it does not use redux structure). I have deleted the unrelated code to keep things simple:
index.ios.js
class ProjectXApp extends React.Component {
constructor(props) {
// Set the use to NULL
this.state = {
user: null,
};
}
handleLogin(user) {
this.setState({
// Update the user state once the login is complete
user,
});
}
renderScene(route, navigator) {
const Component = route.component;
return (
<View style={styles.app}>
<Component
user={this.state.user}
navigator={navigator}
route={route}
/>
</View>
);
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
initialRoute={{
// Render the Login page in the beginning
component: Login,
props: {
onLogin: this.handleLogin.bind(this),
},
}}
/>
);
}
}
Login.js
// Import Facebook Login Util Component
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
// 'false' means responseToken is not required. 'true' means responseToken is required
responseToken: false,
};
}
// This method gets the fb access token, if the token is returned then
// I render the Main App component (switchToMain method). If the
// access token is not returned then I render a login Button (Refer to render method)
async getAccessToken() {
let _this = this;
await (FBSDKAccessToken.getCurrentAccessToken((token) => {
if(!token) {
_this.setState({responseToken: true})
return;
}
_this.setState({responseToken: true});
_this.props.route.props.onLogin({user: true});
_this.switchToMain();
}));
}
switchToMain() {
this.props.navigator.push({
component: Main, // Render the app
props: {
onLogOut: this.onLogOut.bind(this)
}
});
}
componentDidMount() {
this.getAccessToken();
}
onLoginButtonPress() {
// Shows transition between login and Main Screen
this.setState({responseToken: false})
FBSDKLoginManager.logInWithReadPermissions(['public_profile','email','user_friends'], (error, result) => {
if (error) {
alert('Error logging in');
} else {
if (result.isCancelled) {
alert('Login cancelled');
} else {
this.setState({result});
this.getAccessToken();
}
}
});
}
onLogOut() {
this.setState({responseToken: true});
}
render() {
// This component renders when I am calling getAccessToken method
if(!this.state.responseToken) {
return (
<Text></Text>
);
}
// This renders when access token is not available after calling getAccessToken
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this.onLoginButtonPress.bind(this)}
>
<View>
// Login Button
</View>
</TouchableHighlight>
</View>
);
}
}
// Removed the styling code
Logout.js
import { FBSDKLoginManager } from 'react-native-fbsdklogin';
class Logout extends React.Component {
onLogOut() {
FBSDKLoginManager.logOut();
this.props.onLogOut();
this.props.navigator.popToTop();
}
render() {
return (
<View>
<TouchableHighlight
onPress={this.onLogOut.bind(this)}
>
<View
// Styles to create Logout button
</View>
</TouchableHighlight>
</View>
);
}
});
// Removed the styling code
Have you looked at this lib:
https://github.com/lynndylanhurley/redux-auth?