How do I catch changes in state from Firebase Auth? - javascript

I am using Angular 2 with angularfire library. I am having trouble catching changes in the user's state.
First) Logging in works fine. I see the user come through to my subscribe function and all is dandy.
However, When I disable that user on the Firebase console...The user state has changed. Why am I not seeing that change in state come through in my app component?
I would like to captures errors of different types, and handle them according to the error code. To do this, I created a service here:
#Injectable()
export class CZAuthService {
constructor(private af: AngularFire){ }
getAuthState() : Observable<FirebaseAuthState>{
return this.af.auth.catch((error)=>{
console.log(error);
return this.af.auth;
})
}
}
I would like to catch exceptions here in this catch operator, and then return the stream to maintain connection to the stream.
Then in my root app component, I am subscribing to this stream and handling when the user is signed in:
this.auth.getAuthState().subscribe((user)=>{
console.log(user);
if(user != null){
this._store.dispatch(new UserLogInSuccessAction(user))
}
});

Related

Firebase auth onAuthStateChanged resolving to null

I'm trying to get the current user UID from a Firebase database - a simple task in principle. I'm following the guide for managing users from the firebase documentation but I still am unable to get a solution. Everywhere I see that firebase.auth().currentuser will not be defined during initialisation - ok great. I use a listener instead, and the listener fires as it should. But for some reason when it fires, the value of user is null.
export default class ShoppingCategories extends Component {
constructor(props) {
super(props);
this.state = {
GeoFire: new GeoFire(firebase.database().ref('stores-geo').push()),
stores: exstores,
brands: [],
storesSelected: []
}
}
componentDidMount() {
this.getStoreTile();
firebase.auth().onAuthStateChanged((user) =>{
if(user){
this.locateStores(user);
}else{
console.log("No user found: "+user);
}
});
}
...
Not sure what I'm doing wrong here. I get
No user found: null
printed to the console.
Solved my own problem. My service worker was causing the page to be served from cache. I removed the service worker caching feature which fixed the problem. Not exactly sure how to fix this long term right now but will update once I solve.

Angular correct login flow and structure

I am trying to implement a frontend with angular, but I am not sure if my login and overall flow is correct.
I have a login component for the login page which sends the user information to an auth service for authentication, then I save the auth token in the localhost and send it with every get request for the user data, but also I need to check for expired jwt token so I logout the user and clear the localstorage from the information. But I am not sure where this logout should happen.
Also my home page displays 2 different views if the user is logged or not, so I have a boolean in the service that I check. This is my flow:
The login component: Here the error is bind to the html lets say if credentials are invalid
export class LoginComponent implements OnInit {
error : string;
constructor(private authService : AuthService) { }
ngOnInit() {
this.authService.login("Robocop1", "password").subscribe(
data =>{
localStorage.setItem('Authorization', data['token'])
this.auth.isLoggedIn = true
},
err => this.error = err['error']
);
}
}
Service component:
export class AuthService {
isLoggedIn : boolean = false
constructor(private httpClient : HttpClient) { }
login(username, password) {
return this.httpClient.post('http://localhost:8090/login', {
username,
password
})
}
}
This is my home component that checks first if the user is logged:
export class HomeComponent implements OnInit {
isLoggedIn : boolean
constructor(private auth : AuthService) { }
ngOnInit() {
this.isLoggedIn = this.auth.isLoggedIn
}
}
And displays different part of the html:
<div *ngIf="!isLoggedIn">
<p>
hey user
</p>
</div>
<div *ngIf="isLoggedIn">
<p>
not logged
</p>
</div>
So my question is is injetcing a dependencies in the home component ok just to check for single boolean and is there a better way to do it.
Also I can have another data component where I get user data from the database. In the post request I am sending the authentication token so I will have something like:
this.dataService.getItems().subscribe(
data =>{
this.userData = data
},
err => {
if(err['error' === 'Jwt token has expired'){
this.authService.logout()
}else{
this.error = err['error']
}
}
);
So is again injecting dependency just to call a logout method ok? should this logout method be in the authService or elsewhere?
So my question is is injetcing a dependencies in the home component ok
just to check for single boolean and is there a better way to do it.
If your application will be about a couple of simple pages and will not expand, your approach might be enough but for it the best practise is using Angular Route Guards
A route guard is a CanActivate implementation in which you implement your authentication/authorization logic to guard your routes (pages)
So is again injecting dependency just to call a logout method ok?
should this logout method be in the authService or elsewhere?
This should be done implementing an HttpInterceptor. So that you don't need to handle each http call for handling faulty responses or adding authorization tokens. Catching the error response inside your http interceptor and logging out is the way to go. That way you do not have to inject your corresponding service into each place this is required.
HttpInterceptor is also not a big deal. You can follow this step by step guide and implement your own

Emit a boolean from AuthGuard - Angular 4

I use JWT in a server node to check if the user is connected.
AuthGuard in an observable, it will check if my user is connected :
canActivate(): Observable<any> {
if ( !localStorage.getItem('currentUser')){
return Observable.of(false);
}
// Authorization with JWT Token
const options = {
headers: new HttpHeaders().set('Authorization', 'BEARER ' + localStorage.getItem('currentUser') )
};
//Check if the JWT Token is always available and if the signature is right
return this.http.get(environment.api + 'checkToken', options )
.map(() => true).catch(() => {
return Observable.of(false);
});
}
Now I would like to emit the boolean from canActivate to an other component. My other component is the nav-bar of my website. I want to hide some link in the navbar when the user is disconnected. However, I would like to displays some elements when the user is connected.
But even when I use an observable in the constructor of my navbar component, it will check just one time if the user is connected.
Do you have any ideas to emit the boolean from my AuthGuard to my navbar component ?
Thank you
You can use resolve on the route and do almost the same things in resolver class. Then you can access boolean value (or user object itself if you resolve it) from the component by injecting ActivatedRouteSnapshot.
Or if you don't want round trips then you can subscribe to the observable before you return it from canActivate and emit the value to some service that contains Subject for example so you would be able to inject this service into your component and use that subject.

Architecture in a react native app using WebSockets

I have a React Native app I'm going to be building that uses WebSockets. I have a WebSocket library written in JavaScript and I'm simply re-using it for this project, which is fantastic.
My question is, being new to React/React Native, what is the best practice for setting up and maintaining all of the traffic going through the WebSocket?
Initially my idea was to create the websocket in the main App component, something like this:
export default class App extends Component {
constructor(props) {
super(props);
this.ws = new WebSocket;
}
componentWillMount() {
console.log(this.ws);
}
render() {
console.log("We are rendering the App component.....");
return (
<View style={styles.container}>
<Text style={styles.welcome}>Hello, world</Text>
</View>
);
}
}
The actual WebSocket class would contain all of the respective connection handling:
ws.onopen = () => {
// connection opened
ws.send('something'); // send a message
};
ws.onmessage = (e) => {
// a message was received
console.log(e.data);
};
ws.onerror = (e) => {
// an error occurred
console.log(e.message);
};
ws.onclose = (e) => {
// connection closed
console.log(e.code, e.reason);
};
My question is, since the data coming through WebSocket will be applicable for state through many components in the React Native app, but it is not a class that will extend React.Component, do I not interact with Redux in the WebSocket class? Do I move all of the WebSocket connection handling to the App component and dispatch actions there to Redux?
What's the common pattern here to instantiate my WebSocket class and ensure that all traffic in it is properly getting passed to Redux so all component's state will funnel correctly?
Great answers here so far. Just wanted to add that where you keep your data should really be a decision based on what type of data it is. James Nelson has an excellent article on this topic that I refer to regularly.
For your case, let's talk about the first 3 types of state:
Data
Communication State
Control State
Data
Your WebSocket connection is generic and could technically return anything, but it's likely that the messages you're receiving are data. For example, let's say you're building a chat app. Then, the log of all messages that have been sent and received would be the data. You should store this data in redux with a messages reducer:
export default function messages(state = [], action) {
switch (action.type) {
case 'SEND_MESSAGE':
case 'RECEIVE_MESSAGE': {
return [ ...state, action.message ];
}
default: return state;
}
}
We don't have to (and we shouldn't) have any WebSocket logic in our reducers, as they are generic and don't care where the data is coming from.
Also, note that this reducer is able to handle sending and receiving in exactly the same way. This is because the network communication is handled separately by our communication state reducer.
Communication State
Since you're using WebSockets, the types of communication state you want to track may differ from my example. In an app that uses a standard API, I would track when a request is loading, failed, or successful.
In our chat app example, you'll probably want to track these request states whenever you send a message, but there could be other things you want to classify as communication state as well.
Our network reducer can use the same actions as the messages reducer:
export default function network(state = {}, action) {
switch (action.type) {
case 'SEND_MESSAGE': {
// I'm using Id as a placeholder here. You'll want some way
// to tie your requests with success/failure receipt.
return {
...state,
[action.id]: { loading: true }
};
} case 'SEND_MESSAGE_SUCCESS': {
return {
...state,
[action.id]: { loading: false, success: true }
};
} case 'SEND_MESSAGE_FAILURE': {
return {
...state,
[action.id]: { loading: false, success: false }
};
}
default: return state;
}
}
This way, we can easily find the status of our requests, and we don't have to bother with loading/success/failure in our components.
However, you might not care about the success/failure of any given request since you're using WebSockets. In that case, your communication state might just be whether or not your socket is connected. If that sounds better to you, then just write a connection reducer that responds to actions on open/close.
Control State
We'll also need something to initiate the sending of messages. In the chat app example, this is probably a submit button that sends whatever text is in an input field. I won't demonstrate the whole component, as we'll use a controlled component.
The takeaway here is that the control state is the message before it's sent. The interesting bit of code in our case is what to do in handleSubmit:
class ChatForm extends Component {
// ...
handleSubmit() {
this.props.sendMessage(this.state.message);
// also clear the form input
}
// ...
}
const mapDispatchToProps = (dispatch) => ({
// here, the `sendMessage` that we're dispatching comes
// from our chat actions. We'll get to that next.
sendMessage: (message) => dispatch(sendMessage(message))
});
export default connect(null, mapDispatchToProps)(ChatForm);
So, that addresses where all of our state goes. We've created a generic app that could use actions to call fetch for a standard API, get data from a database, or any number of other sources. In your case, you want to use WebSockets. So, that logic should live in your actions.
Actions
Here, you'll create all of your handlers: onOpen, onMessage, onError, etc. These can still be fairly generic, as you've already got your WebSocket utility set up separately.
function onMessage(e) {
return dispatch => {
// you may want to use an action creator function
// instead of creating the object inline here
dispatch({
type: 'RECEIVE_MESSAGE',
message: e.data
});
};
}
I'm using thunk for the async action here. For this particular example, that might not be necessary, but you'll probably have cases where you want to send a message then handle success/failure and dispatch multiple actions to your reducers from within a single sendMessage action. Thunk is great for this case.
Wiring It All Together
Finally, we have everything set up. All we have to do now is initialize the WebSocket and set up the appropriate listeners. I like the pattern Vladimir suggested--setting up the socket in a constructor--but I would parameterize your callbacks so that you can hand in your actions. Then your WebSocket class can set up all the listeners.
By making the WebSocket class a singleton, you're able to send messages from inside your actions without needing to manage references to the active socket. You'll also avoid polluting the global namespace.
By using the singleton set up, whenever you call new WebSocket() for the first time, your connection will be established. So, if you need the connection to be opened as soon as the app starts, I would set it up in componentDidMount of App. If a lazy connection is okay, then you can just wait until your component tries to send a message. The action will create a new WebSocket and the connection will be established.
You can create dedicated class for WebSocket and use it everywhere. It's simple, concise and clear approach. Moreover you will have all stuff related to websockets encapsulated in one place! If you wish you can even create singleton out of this class, but the general idea is this:
class WS {
static init() {
this.ws = new WebSocket('ws://localhost:5432/wss1');
}
static onMessage(handler) {
this.ws.addEventListener('message', handler);
}
static sendMessage(message) {
// You can have some transformers here.
// Object to JSON or something else...
this.ws.send(message);
}
}
You have only run init somewhere in index.js or app.js:
WS.init();
And now you can loosely send message from any application layer, from any component, from any place:
WS.sendMessage('My message into WebSocket.');
And receive data back from WebSocket:
WS.onMessage((data) => {
console.log('GOT', data);
// or something else or use redux
dispatch({type: 'MyType', payload: data});
});
So you can use it everywhere even in redux in any action or somewhere else!
There are no official guidelines about that. I think using a component is confusing because it will not be rendered, and I guess if you use Redux you want to share the data from websocket anywhere in the application.
You can give the dispatch function to your Websocket manager.
const store = createStore(reducer);
const ws = new WebSocketManager(store.dispatch, store.getState);
And use this.dispatch inside your class methods.
// inside WebSocketManager class
constructor(dispatch, getState) {
this.dispatch = dispatch;
this.getState = getState;
}
You can also use middlewares to handle side effects, I think it is the recommended way. There are two great libraries that you can look :
redux-saga
redux-observable

Returning callback from service to component in React + Flux

Have a question about the proper implementation of Flux with ReactJS.
Lets say I have a contact form which calls my ContactService on submit, passing the form information.
ContactService.js
import request from 'superagent';
import when from 'when';
import ContactActions from '../actions/';
let constants = require('../constants.js');
const BASE_URL = constants.default.BASE_URL;
class ContactService {
submitFormData(formData) {
request
.get(BASE_URL + 'api/v1/contact')
.end(function(err, res){
if (!err && res){
// This is where my question is
} else {
console.log("There has been an error submitting contact form to API");
console.log(err)
// This is also kind of where my question is
}
})
}
}
export default new ContactService();
Now, I want to notify my component whether the submission was successful. My question is what is the best way to do that? If I were retrieving data from the API, or needed to change the state of my component, I would handle it by passing the response to an Action, and saving the data in Store, which the component could subscribe to.
But here I just need a response so that I can show a confirmation or error message. Should that still be passed through an action and store? Or is there a better way, like returning a promise directly to the component so that it can run a callback function without involving the store at all?
Always use store/flux actions for that kind of thing.
Dispatch a data_received, data_error from the Promise handlers. It's more semantic, easier to debug and uses the same flow of data as everything else (action -> store -> view).
All the data retrieving in a flux architecture has to be done through stores and actions

Categories

Resources