Redux state is updated but UI is not updating - reactjs

I have created simple app to add user using redux and antd library. When user is added I am trying to show success message. I am able to get that updated message in state but when I alert that message it shows blank. When I again click the button then it shows success message in alert.
I have created codesandbox link : https://codesandbox.io/s/admiring-waterfall-v04g9
Please help me out, I am quite new to react.

here is what possibly happened
- since your callback function is synchronous, eventhough the addUser function is placed before alert function, it is not a guarenty that it will execute before it.
solution is to make your function asynchronous as follows to guaranty that the user is added and hence state updated (with the user and the message you are displaying) before the alert is fired. make sure to save changes and refresh the sandbox to test it.
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields(async (err, values) => {
if (!err) {
await this.props.addUser(values);
alert(this.props.message);
}
});

Related

React-Native unable to store state getting null

I'm new to React-native so if there is a misunderstanding please be super clear and treat me as if I have never seen React-native before.
I have the app so that when you press on a button it will send you into an Auth0 flow where you can log in to the app. This seems working. If I log out the access token directly in the callback I am successful in getting it at the credentials.accessToken variable/location. However, when I am trying to set the state of the accessToken variable I get back null when I try to log it out to the screen via an alert or even via console.log. What am I doing wrong to cause this? I tried searching SO and google but both seem to show this as the right way of doing it.
Code:
const [accessToken, setAccessToken] = useState(null)
const onLogin = () => {
auth0.webAuth
.authorize({
scope: 'openid profile email'
})
.then(credentials => {
setAccessToken(credentials.accessToken)
Alert.alert('Access token: ', accessToken)
})
.catch(error => console.log(error)) // Eventually send this to backend for crash reporting
}
This is probably a case of a state not updating immediately. Try to use a useRef() instead of a useState(https://www.w3schools.com/react/react_useref.asp). If the problem is solved the issue was with the fact that states are updated asynchronously and hence it was not set to its most recent value (the value you expected) when you console logged it.

UserEvent doesn't wait for dialog to be loaded when it is lazy load

After updating testinglibrary/userEvent from version 13 to 14, it is not waiting for dynamically rendered.
My dialog is lazily loaded as well as the content inside the dialog.
An example code is below.
it('updates the channel information after edit channel request succeeds', async () => {
render();
await userEvent.click(await screen.findByTestId('TestId'));
const myDialog = await screen.findByRole('dialog');
// This is problematic.
const nameField = within(myDialog).getByLabelText(/name/i);
})
Dialog shows spinner until it finishes fully loading the content.
And the content will be rendered as long as query waits. But it doesn't wait for the content to be rendered but quits waiting as soon as it finds the spinner, saying it couldn't find the content but only spinner.
What I tried
Using find query instead of get, some tests are resolved only doing this but others aren't.
Using screen instead of within(dialog).findBy. This resolves some breaking test as well.
I looked over the document and changelog if there were effective change that possibly breaks the test code, but had no luck :(
What should I do with it?
This might be because you haven't ran setup yet. userEvent's API have changed in 14, and now, per the documentation:
We recommend invoking userEvent.setup() before the component is rendered.
So in your case, you need to try something like this.
it('updates the channel information after edit channel request succeeds', async () => {
const user = userEvent.setup()
render();
await user.click(await screen.findByTestId('TestId'));
const myDialog = await screen.findByRole('dialog');
// This is problematic.
const nameField = within(myDialog).getByLabelText(/name/i);
})

Unable to set up invisible reCAPTCHA verifier for multi-factor authentication in a react app

As per this article, https://cloud.google.com/identity-platform/docs/web/mfa, I am trying to set up invisible reCAPTCHA. However, the callback function does not seem to fire. The idea is that I want the recaptcha to fire off upon a button click and send a code via the callback function but it is not working.
I am trying to activate the recaptcha via the following function linked to a button with the 'code-button" id.
sendCode () {
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('code-button', {
'size': 'invisible',
'callback': () => {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
// onSolvedRecaptcha();
console.log("captcha is working")
}
})
recaptchaVerifier.render()
}
When I press the button to fire off the sendCode function, the callback inside the recaptchaVerifier does not seem to work. It is supposed to console.log "captcha working" but it does not as I check the console.
I do get the following issues in the console but I am not sure if they are actually blocking the callback or making the recaptcha not work:
Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute
SharedArrayBuffer usage is restricted to cross-origin isolated sites
I do not even know how to resolve them. As per some articles, they seem to be issues that can only be resolved by Google itself.
Does anyone know why this is happening?
Thanks.
I solved this issue myself by dropping the callback from within and instead I simply called recaptchaVerifier from another function as needed. For example:
First, initialize the recaptcha and render it:
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('code-button', {
size: 'invisible'
});
recaptchaVerifier.render()
Then, simply call it where needed:
user.multiFactor.getSession().then((multiFactorSession) => {
// Specify the phone number and pass the MFA session.
const phoneInfoOptions = {
phoneNumber: this.state.number,
session: multiFactorSession
};
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(
phoneInfoOptions, recaptchaVerifier);
})

Why componentDidUpdate is executing repeatedly

I am trying to display user notes on submit. On componentDidMount I am sending a GET request to the server to initially display data. When a user submits a new comment, on componentDidUpdate I'm checking prevState. If there is any difference found it should load new data from the server.
But inside componentDidUpdate continuous request is sending to the server.
What I have done so far
componentDidUpdate(prevProps, prevState){
if(prevState.status !== this.props.userDisplayNotes.status){
// This is GET request to display the data from the server
this.props.displayUserNotes(this.props.user_id)
}
}
// Here I'm displaying data on initial rendering with GET request
componentDidMount(){
this.props.displayUserNotes(this.props.user_id)
}
// This is form submit handler
handleSubmit = (e) => {
e.preventDefault();
this.props.saveUserNote(this.props.user_id, this.state.userNote)
}
Upon successful submission of comment I'm getting a response from server like {"status":"success"}
For state management I'm using Redux.
But inside componentDidUpdate it is sending continuous request to server causing application crashed. Can someone please explain me what I'm doing wrong here?
You can compare previous Props with new one it will fix your problem
componentDidUpdate(prevProps, prevState){
if(prevProps.userDisplayNotes.status !== this.props.userDisplayNotes.status){
this.props.displayUserNotes(this.props.user_id)
}
}

Flux architecture for a login or basically most forms processing

I am trying to understand a bit more about flux architecture and am designing a simple login component. Suppose when you login (POST ajax) and an error comes back. How would the information flow in flux?
I think the LoginComponent should do the work on a handleSubmit function.
After the ajax call comes back with an error and message should the component create an action such as "UpdateLoginStatus with payload {message: "no e-mail found"}. This would then trigger a LoginStore or something to save the status message and then it would emit an event such as "LoginStatusMessageChanged".
Another totally different component called LoginStatusMessage would register to listen to events on the LoginStore. It would get notified of this event and then proceede to update it's own state with the message. It would go out to LoginStore and fetch the message and display it to the user via render.
I believe this example covere your question quite well: https://github.com/przeor/react-router-flux-starter-kit/
Don't let your Component do the request. That would be mixing UI with business logic. That is always bad.
Entered username, password and button should be handled by your React component. Whenever the button gets clicked, the component should trigger an action.
//Component.js
handleSubmit: function(){
UserActions.login(this.state.username, this.state.password);
}
The action informs the store:
//UserActions.js
login(username, password) {
this.dispatch({username: username, password: password});
}
The Store then executes the needed AJAX (as the actions never should cause changes or requests themselves).
Depending on success or error, your store then triggers a new action. It should never save the response directly. Never save data in stores without an preceding action. If you want to, you can save that you are currently logging in (For instance, if you want to animate a spinner)
//UserStore.js
handleLogin(credentials) {
this.isLoggingIn = true;
AuthService.login(credentials.username, credentials.password).then((user) => {
UserActions.loginSuccess(user);
}).catch((errorMessage) => {
UserActions.loginFailed(errorMessage);
})
}
The actions again do their dumb thing, as they always should be nothing but dumb messengers.
//UserActions.js
loginSuccess(user) {
this.dispatch(user);
}
loginFailed(errorMessage) {
this.dispatch(errorMessage);
}
Up next: handle the actions in your store!
//UserStore.js
handleLoginSuccess(user) {
this.user = user;
this.isLoggedIn = true;
this.isLoggingIn = false;
}
handleLoginFailed(errorMessage) {
this.errorMessage = errorMessage;
this.isLoggingIn = false;
}
That's it. As long as your component listens to the UserStore, it get's informed when your user logs in, is successfully logged in or had an error, while having a clear separation of Logic and UI and a unimanual flow.
EDIT: Code examples are mostly pseudocodish. Actual implementation depend on your Flux framework.

Resources