Firebase and React - check user auth status - reactjs

I'm working on app based react+mobx and as backend use the firebase.
Currently on the app start i need to check if user is logged in.
I'm doing it with firebase.auth().onAuthStateChange listener, but because it's async function - the first response always null.
So my current solution is display some loading message and put setInterval function with status checking in componentWillMount lifehook.
The question is - is there any more elegant solution to this issue?

Before you call firebase.auth().onAuthStateChange, modify your state to be something like: state.authenticatedUser: 'pending'. Have your observer change that state to real user info once it is called.
Have your components take into account state.authenticatedUser when rendering and render either "authentication pending" or "authenticate user"

Related

Initializing component with parameter set from other page in nextjs

I have 2 components on separate pages in nextjs. The way I would like my app to work is:
User inputs some data on page A and clicks submit
A request to my backend is sent and it returns a 'accessToken', at the same time the user is redirected to page B
To load page B the 'accessToken' is sent to an external service to initialize the component provided by that service
If the user leaves the page and returns, the 'accessToken' should be still set and they should not need to re-do step 1,2 but if they request a new one then that should also be updated in page B
Below the component provided by the external service for reference:
<WebSdk
accessToken={token}
expirationHandler={handler}
config={config}
options={options}
onMessage={messageHandler}
onError={errorHandler}
/>
How should I store and read the access token? Do I need to use useState or useEffect? Do I need to set a cookie or localStorage?
Neither useState nor useEffect is good choice for this condition.
You can use both cookies(low security) and localStorage , but I recommend using sessionStorage(it has expire time) .I

How can i call this action from my saga generator function?

Im in React v16, Redux, saga 1.1.3, AWS cognito for UserMgmt
Requirements:
after creating a new user, email them a password reset link so they can log in and set their password
password reset action works perfectly
new user creation works perfectly
I need to call the pwd reset action once the new user is created. I'm targeting the saga as a good place to make this call. Once all the yields for the existing saga are done, right before setting state with put, i make one more yield call to the other action i want to run...and never see it do anything : )
is there a trick to running or dispatching actions from sagas.
this is the one line i need to run
cognitoActions.forgotPwd(email);
running it from my front end works every time.
also, it is imported
import { cognitoActions } from "fakepath/cognito";
on the front end mapping the action to props, passing it to the component, then calling it works every time...
just no action from the saga. i've tried logging results and dont think its running at all, no console.log happens...
You can use the "put" function to call it from within an effect like this:
yield put(action)
Potentially depending on what you want you can use:
putResolve(action)
You can find documentation for this here:
https://redux-saga.js.org/docs/api/

How to avoid letting an async thunk that is no longer useful (the app is not expecting it anymore) from being able to update the state?

I have the following pattern on my single page app (React + Redux).
It runs every time a load a page on the app. User navigates to a specific page, and the loadPageThunk is dispatched. The initial state of the page shows a spinner to the user. This is used for example, in a blogpost page.
That thunk will get some async data (the blogpost), and then will show the page with that data.
It works fine. When the user navigates away from the page. A useEffect dispatches a RESET action to reset the state back to its initial value.
My question is:
What if the async call takes too long to complete and the user navigates away? It will create a problem because now there's a pending promise that will complete in an unexpected time. How can I prevent that completion from updating my state?
Imagine the following steps for an async call that is taking 10 seconds to complete:
#### FIRST PAGE LOAD ####
USER VISITS blog/slug-1
loadPageThunk() IS DISPATCHED
blogPost1 STARTS GETTING FETCHED (WILL TAKE 10 SECONDS)
USER NAVIGATES AWAY
#### SECOND PAGE LOAD ####
USER VISITS blog/slug-2
blogPost2 STARTS GETTING FETCHED (WILL TAKE 10 SECONDS)
USER IS STILL SEEING SPINNER
blogPost1 (FROM THE PREVIOUS VISIT) HAS COMPLETE AND WILL UPDATE THE STATE
USER NOW SEES blog/slug-2 WITH THE DATA FROM blogPost1 WHICH IS AN ERROR
blogPost2 WILL EVENTUALLY COMPLETE AND USER WILL SEE A CONTENT FLICKER ON THE PAGE
QUESTION
How can I avoid pending promises that are no longer useful from being able to update the state?
This problem is not currently happening in my app, but I think that a good design should account for that.
Should I add an ID for my LOAD_PAGE cycle, so I can check the ID of the current cycle before allowing callbacks / async code from updating the state when IDs don't match? How do people usually handle this?
Personally I store blog data as entities (posts, comments, etc.) keyed by id and collections. The collection is just the array of post ids on a particular page.
For example,
{
entities: {
posts: {
1: {...},
2: {...}
},
comments: {
123: {...},
999: {...}
}
},
collections: {
"blog/slug-1": [99,98,97...],
"blog/slug-2": [89,88,87...],
}
}
This sort of structure means that every page can save its data in the correct place regardless of whether it is the current page or not. It also means that every page can select its own data and can see whether that data already exists in the state.
The promise returned by createAsyncThunk has an abort() method attached which can be used to 'cancel' the promise. See canceling while running. You can call abort() in your cleanup to prevent the thunk from being fulfilled.
In your reducers, if you are handling the rejected case for your thunk, then you can add an exception for cases where the error name is AbortError to do nothing instead.
To expand a bit about your specific situation: a good rule of thumb is that if you find yourself 'resetting' state when you unmount the component, then it should have just been local component state in the first place.

Is it normal in React to use `useState` to manage whether a form has been submitted?

A basic online React tutorial is demonstrating how to create a React-based form with 3 fields (first name, last name, and email). Surprisingly to me, it has useState to manage whether or not a form has been submitted, which it uses to decide on whether to show a success message or not.
Please note that it does NOT make an actual form submission (i.e. no API calls) and so I am wondering whether it is using state only for simulation purposes here.
Here is a snippet:
const [submitted, setSubmitted] = useState(false);
...
{submitted && !values.lastName && <span id='last-name-error'>Please enter a last name</span>}
...
{showSuccess && <div class='success-message'>Success! Thank you for registering</div>}
...
Is it normal for real-world React applications to useState to manage whether or not a simple form such as 'contact us' or 'feedback', etc, has been submitted? My guess is that normally there would be no need to do so.
As the resulting API call, whether 'success' or 'fail' could simply be used to show the state of the error message. Thereafter, the form should ideally reset itself to allow for another submission. So, there would be no need to store the state of the submitted form. Am I correct in my understanding?
Your question is a little confusing. basically if you want to store a data in React and this data has direct effect on your application you mostly should save it in state. When you submit a form, the form onSubmit event handler will be called and you can do everything in that event handler. It's clear that in the tutorial submitted state is a flag to simulate the fetch process. Usually when you want to handle submitting a form and fetching API you should store 2 items in state:
Error and Loading
You should use loading flag to show a loading indicator during fetching API and use error to check if any error exist store and show it. If API fetches successfully you may redirect user to another page, show a notification or change some data in your state. It's up to you. But be sure the submitted state in your tutorial is just an example ans simulation. But it has real usages in real world! Hope it helps!
Here is an example: I want to add a user by fetching an api and i want if api fetches successfully add it to the list:
Sandbox

Dispatching clear state action in redux

I'm using redux in my react project. My question is how to clear state when some works that use state finished.
For example, I have search state in my redux store.
search:{
status: 'INIT',
result: [],
}
Since my search is an async request, it has status field.
when the user searches a word, it will dispatch 'FETCH_SEARCH' to make status to 'LOADING'.
when fetch done, it will dispatch 'SUCCESS_SEARCH' or 'FAILURE_SEARCH' to make status 'SUCCESS' or 'FAILURE'.
And in my component that shows the result of a search, it renders depend on search state's status. If a status is 'SUCCESS', it will render the result of the search.
So far, there is no problem.
but what if the user has searched before and try to search again after some works? Since the user has successfully searched before, search state has 'SUCCESS' state. So my component will render 'unwanted' result.
So currently, i dispatch 'CLEAR_SEARCH' action to initialize search state.
My question is how to clear redux state after some submission has done.
Am i doing correctly? Or is it anti-pattern?
I've done this before and what I do is follow a workflow.
After a search submission you shouldn't clear state. You should reset it when the user searches again.
Let's say the user searches "Term A". You "SEARCH_SUCCESS" is set and it's rendering the results. When he searches again put that state to "SEARCHING" or "LOADING" as you have it.
Now in your render method if you have something like
// etc..
if (isLoading) {
return <LoadingComponent />
}
// etc..
You will render a loading before rendering any results. Then your search action should set either the SUCCESS or FAILURE and if you have your components mapped out correctly it should be really straightforward.
EDIT
After a brief discussion in the comment section you wanted INIT only at the start (the first ever time it's rendered) but then resetting the state still.
So you can go for this workflow:
First time:
-> INIT -> SEARCH_TRIGGERED -> LOADING -> SUCCESS or FAILURE
Second time (still in same screen):
-> SEARCH_TRIGGERED -> LOADING -> SUCCESS or FAILURE
And then you would have the desired workflow.
Hope I helped

Resources