How to automatically click submit button - react - javascript

I have a react login page with username and password manually inputted,
I want the submit button to automatically click upon page load so it will automatically log in users.
Here is my code.
export const LoginForm = () => {
const history = useHistory();
const classes = useStyles();
const email = 'email#email.com';
const password = 'mypassword';
const [authStatus, setStatus] = useState(null);
const [isSpinnerHidden, setSpinner] = useState(true);
const { session } = useContext(SessionContext);
const recaptchaRef = useRef();
const _onSubmit = async (e) => {
e.preventDefault();
setSpinner(false);
const authResult = await session.signIn(email, password);
setSpinner(true);
console.log(session);
authResult ? setStatus(authResult) : history.push('/dashboard');
};
return (
<form onSubmit={_onSubmit}>
<Typography
align='center'
color='primary'
variant="h4"
style={{ marginBottom: '20px' }}
>
Sign In
</Typography>
{authStatus ?
<Alert
severity="error"
>
{authStatus}
</Alert>
:
null
}
<TextField
type='email'
label="Email"
/>
<TextField
type='password'
label="Password"
/>
<Link
onClick={() => history.push('/restore')}
className={classes.restore}>
Forgot password?
</Link>
<MuiButton
text='Sign In'
type='submit'
value='login'
isSpinnerHidden={isSpinnerHidden}
className={classes.button}
/>
</form>
);
};
what can I add to this code or change that will make it click on the sign-in button automatically and login the user.

In order to automatically click on the submit button, you need to use an onLoad
convert your _onSubmit to a windows onload, something like this
window.onload = async (e) => {
e.preventDefault();
setSpinner(false);
console.log('hello');
const authResult = await session.signIn(email, password);
setSpinner(true);
console.log(session);
authResult ? setStatus(authResult) : history.push('/dashboard');
}

I don't think clicking the button automatically is the best experience you can have here.
The better way of doing that here would be to conditionally choose the route based on authentication state before you even render the login screen. Something like this:
if (isAuthenticated){
history.push('/dashboard);
} else {
history.push('/login');
}
If for whatever reason you NEED to do it your way, just call your signin function when the components mounts with useEffect
import React, {useEffect} from 'react';
export const LoginForm = () => {
...
useEffect(() => {
if(isAuthenticated){ // You'll need to get the auth state from somewhere here
history.push('/dashboard')
}
},[])
return (
...
);
};

Related

How to send "token" to "Api" in "react"

I'm a new developer.
If you login to our website, JWT will be created.
When I press the button, I have to put it in the API as a backend.
And if the screen is successful, the address in the API must be printed out.
If it fails, 'authentication failure' should be displayed on the screen.
I want to do this. Please help me.
import axios from 'axios';
import React, { useState } from 'react';
import { Button } from '#material-ui/core';
function TestPage() {
const onLogin = () => {
var variables = {
email: email,
password: password,
};
Axios.post('/auth/login', variables).then((res) => {
setCookie('token', res.payload.accessToken);
setCookie('exp', res.payload.accessTokenExpiresIn);
Axios.defaults.headers.common['Authorization'] = `Bearer ${res.payload.accessToken}`;
Axios.get('/user/me').then((res) => {
console.log(res);
});
});
};
return (
<>
<div>
<Button
variant="contained"
color="primary"
style={{ width: '200px' }}
onClick={(e) => customFetch(e)}>
address
</Button>
</div>
{address && <div>{address}</div>}
</>
);
}
export default TestPage;
Generally for any network operation, it's helpful to know when it's in progress, has finished, and/or has an error. Let's set this up:
const [isLoading, setIsLoading] = useState(false)
const [data, setData] = useState(null)
const [error, setError] = useState(null)
// inside your `onLogin` function...
setIsLoading(true);
Axios.post('/auth/login', variables).then((res) => {
setCookie('token', res.payload.accessToken);
setCookie('exp', res.payload.accessTokenExpiresIn);
Axios.defaults.headers.common['Authorization'] = `Bearer ${res.payload.accessToken}`;
// bit messy using the same error state for both but you can always refactor
Axios.get('/user/me').then((res) => {
console.log(res);
setData(res); // not sure where the actual data is with Axios
}).catch(err => setError(err);
}).catch(err => setError(err));
setIsLoading(false);
During your POST, set the state variables accordingly:
Before the post, setIsLoading(true)
On success, setData(response.data) // whatever your payload might be
On error/failure, setError(error)
Now in your component return, you can conditionally render your different states, e.g:
// your component body
if (isLoading) return (
// a loading state
)
if (error) return (
// an error state
// e.g. "Authentication Failure"
)
return (
// your success/ideal state
// e.g:
<>
<div>
<Button
variant="contained"
color="primary"
style={{ width: '200px' }}
onClick={(e) => customFetch(e)}>
address
</Button>
</div>
{address && <div>{address}</div>}
</>
)
Alternatively, you could leverage the variables slightly differently:
return (
<>
<div>
<Button
variant="contained"
color="primary"
style={{ width: '200px' }}
onClick={(e) => customFetch(e)}
disabled={isLoading}>
address
</Button>
</div>
<div>
{isLoading
? 'Checking...'
: error !== null
? 'Something went wrong'
: 'Ready to submit'}
</div>
</>
)
The ternary style can be a bit messy though.

How do I only re-render the 'Like' button in React JS?

const SiteDetails = ({site, user}) => {
const dispatch = useDispatch()
const updateSite = async (siteId, siteObject) => {
try {
const updatedSite = await siteService.update(siteId, siteObject)
dispatch(toggleStatus(siteId, updatedSite))
// dispatch(setNotification(`One like added to ${updatedSite.title}`))
} catch (exception) {
console.log(exception)
dispatch(setNotification("Could not update site"))
}
}
return (
<div className='site-details'>
<Link href={site.url}>{site.url}</Link>
<h2>
<LikeButton user={user} site={site} updateSite={updateSite} />
<VisitButton user={user} site={site} updateSite={updateSite} />
</h2>
<p>{site.description}</p>
<img src={site.imageUrl} alt={"Image could not be loaded"} />
</div>
)
}
const LikeButton = ({user, site, updateSite}) => {
const dispatch = useDispatch()
const likedList = site?.userLiked.find(n => n?.username === user.username)
useEffect(() => {
if (!likedList) {
const newUser = { username: user.username, liked: false }
const updatedArray = site.userLiked.concat(newUser)
const updatedSite = {...site, userLiked: updatedArray}
updateSite(site.id, updatedSite)
}
},[])
const liked = likedList?.liked
const handleLike = async () => {
const indexCurr = site.userLiked.indexOf(likedList)
//updatedSite is the parent site. This will have its liked status toggled
//actually updatedUserLiked can simply use username: user.username and liked: true
const updatedUserLiked = { username: likedList?.username, liked: !likedList.liked}
site.userLiked[indexCurr] = updatedUserLiked
const updatedSite = {...site, userLiked: site.userLiked}
updateSite(site.id, updatedSite)
//childSite is the spawned from the parent,
//it will contain a parent, which is the updatedSite
const childSite = {...site, parent: updatedSite, opcode: 100}
const newSite = await siteService.create(childSite)
// dispatch(createSite(newSite))
dispatch(initializeUsers())
dispatch(initSites())
}
return (
<Button
size='small' variant='contained'
color={liked ? 'secondary' : 'primary'}
onClick={!liked ? handleLike : null} className='site-like'>{liked ? 'Already Liked' : "like"}
</Button>
)
}
Expected Behaviour
Actual Behaviour
Hi everyone, my goal is to make it such that when the 'Like' button is clicked, the appearance of the button will change but the rest of the page does not refresh. However, if you look at the actual behaviour, after the button is clicked, the page is re-rendered and is restored to its default state. I have made my own component which upon clicking will display further details below.
I have tried looking at React.memo and useRef, none of which worked for me. Help on this would be very much appreciated. Thanks!
Have tried using the 'useState' hook?
import {useState} from 'react'
function LikeButton() {
//set default value to false
const [liked, setLiked] = useState(false);
const handleClick = () => {setLiked(!liked)}
return(
<Button color={liked? 'secondary' : 'primary'} onClick={() => handleClick()}
/>
);
}
export default LikeButton;
this should only re-render the button
check this out as well:
ReactJS - Does render get called any time "setState" is called?

Too many re-renders. React limits the number of renders to prevent an infinite loop. Passing parameters with context API

I am using React context to get the login function and error which is defined in the context provider file to login in into the firebase database, and use the thrown error in login to display it in the app.
My problem is I didn't get any error when I just use the error thrown from the firebase auth to display the error in the app, but I also added other errors like empty fields to also show an error field in the app.
After doing that I get this too many re-renders error. I think this error is due to using multiple if statements in the function. Can you please suggest a new option or if this is wrong explain please.
Context Provider file
import React from 'react';
import auth from '#react-native-firebase/auth';
export const AuthContext = React.createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = React.useState(null);
const [error, setError] = React.useState('');
return (
<AuthContext.Provider
value={{
user,
setUser,
error,
login: async (email, pwd) => {
try {
await auth().signInWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
register: async (email, pwd) => {
try {
await auth().createUserWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
logout: async () => {
try {
await auth().signOut();
} catch (e) {
console.log(e);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
App file
import React from 'react';
import {Button, Image, Text, TouchableOpacity, View} from 'react-native';
import styles from '../styles/Styles';
import FormInput from '../components/FormInput';
import FormButton from '../components/FormButton';
import SocialButton from '../components/SocialButton';
import {AuthContext} from '../navigation/AuthProvider';
import ErrorText from '../components/ErrorText';
const LoginScreen = ({navigation}) => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
if (error) {
setErrorForwarded(error);
}
if (!email || !password) {
setErrorForwarded('fields-empty');
}
const renderErrorText = e => {
if (e.code === 'auth/invalid-email') {
return <ErrorText errorText="Email invalid!" />;
}
if (e.code === 'auth/user-not-found') {
return <ErrorText errorText="User not found!" />;
}
if (e.code === 'auth/wrong-password') {
return <ErrorText errorText="Wrong password!" />;
}
if (e === 'fields-empty') {
return <ErrorText errorText="Fields cannot be empty!" />;
}
};
return (
<View style={styles.loginContainer}>
<Image
source={require('../assets/rn-social-logo.png')}
style={styles.loginLogo}
/>
<Text style={styles.loginText}>Sign In</Text>
<FormInput
labelValue={email}
onChangeText={email => setEmail(email)}
placeholderText="Email"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={password}
onChangeText={pwd => setPassword(pwd)}
placeholderText="Password"
iconType="lock"
secureTextEntry={true}
/>
{error ? renderErrorText(errorForwarded) : null}
<FormButton
buttonTitle="Sign In"
onPress={() => {
{
email && password ? login(email, password) : {};
}
}}
/>
<TouchableOpacity style={styles.loginForgetBtn}>
<Text style={styles.loginNavBtnText}>Forgot Password?</Text>
</TouchableOpacity>
<SocialButton
buttonTitle="Sign In with Facebook"
buttonType="facebook-square"
color="#4867aa"
backgroundColor="#e6eaf4"
/>
<SocialButton
buttonTitle="Sign In with Google"
buttonType="google"
color="#de4d41"
backgroundColor="#f5e7ea"
/>
<TouchableOpacity
style={styles.loginForgetBtn}
onPress={() => navigation.navigate('Signup')}>
<Text style={styles.loginNavBtnText}>
Don't have an account? Create here...
</Text>
</TouchableOpacity>
</View>
);
};
export default LoginScreen;
The reason why you are coming across multiple rerenders have nothing to do with the if condition in your function. By running the functions to set the state directly within the component's function, you are forcing a rerender, after which it starts to run the function from top to bottom, where it again sets the state.
Only react hooks are not reinitialized/run and can be prevented from running on every subsequent rerender, so you will need to use the useEffect() hook with an array of dependencies to watch, so that you don't run into unnecessary state changes on rerenders.
I'm going to include changes for the relevant bits of the code(before the return statement on App component)
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
React.useEffect(() => {
if (error) {
setErrorForwarded(error);
}
}, [error]) //using an array of dependencies like this ensures that the function only runs on changes in the error state
React.useEffect(() => {
if (!email || !password) {
setErrorForwarded('fields-empty');
}
}, [email, password]) //similarly, only run this hook for changes in email or password
Thank you all, I knew the problem that causes the re-render was that multiple if statements directly in the function component, I just couldn't figure out how to overcome that.
It worked when I use a function to check those if conditions to set those state and call that function in button submit before calling the API. But I think useEffect hook does it much better, Thank you all in clarifying me.
Can I clarify something else, say at first error variable is empty so errorForwarded will be set to empty. Now on the re-render again errorForwarded will be set to empty. So my question is even state change is detected the actual state value hasn't changed. Then why re-render occurrs. Thanks.

Functional Components: Accessing Shared States

How can I alter the state of the hook isSignup per click of a button and return it to Auth.js using functional components?
I can't figure out how to wrap the return statement inside the button. I keep getting _onClick is not a function error.
Note: Homepage.js and Auth.js are functional components and they are using shared states.
// Homepage.js
const Homepage = () => {
const [isSignup, setIsSignup] = useState(false);
const handleClick = (e) => {
if (e) {
return <Auth isSignup={true}></Auth>
}
return <Auth isSignup={false}></Auth>
}
return (
<div>
<Button component={Link} to="auth" onClick={() => handleClick(false)}>
login
</Button>
<Button component={Link} to="auth" onClick={() => handleClick(true)}>
signup
</Button>
</div>
}
// Auht.js
const Auth = (props) => {
if(props.isSignup) {
// display signup form....
}
onClick is expecting a function, so,
onClick={handleClick}
The signature of handleClick is like this,
const handleClick = (event : React.ChangeEvent<any>) => {}
From the event, you can get the button id or something to determine the action.

cant get the updated profile info with firebase after signIn with email

I am currently developping an app using react native and i could manage to have a login and sign up page but my problem is the following.
After create user with email and password using firebase method, i would like to update the profile info (displayName) in order to display it in the home page.
But it seems that the page redirect to the home page after sign up without the update done
I have set a listener on my navigator stack to display login/signup pages or Home page regarding the value of user.
the Update is correctly set if i close the app and reload it after the first sign up success.
my code is the following
the main stack code
function onAuthStateChange(user) {
setUser(user);
if (initializing) setInitializing(false);
}
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChange);
return subscriber;
}, [];
if (initializing) {
return <LoadingScreen />
if (!user) {
return (
<NavigationCOntainer>
<AuthStackScreen />
</NavigationCOntainer>
);
}
return (
<NavigationCOntainer>
<DrawerStackScreen />
</NavigationCOntainer>
the code to handle the sign up method :
function handgleRegister() {
auth()
.createUserWithEmailAndPassword(email, password)
.then(userCred => {
return userCred.user.updateProfile({
displayName: name,
});
})
.catch(e => {
...
...
});
}
the code in the Home page, i also set a listener of user.
I also have tried by calling the method : auth().currentUser;
But i got the same problem, the displayName at the first display was set to null and i had to close and reload the app to be able to display it.
function onAuthStateChange(user) {
console.log(user);
}
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChange);
return subscriber;
}, [];
the result of the log shows that displayName is null so i assume the sign up process redirect to the home before updating the value.
Does someone has an idea how i can manage to get the update value on the Home page screen?
Thanks in advance
The user's profile information is gotten from their ID token, which Firebase gets then the user signs in (or is created) and then automatically refreshes every hour. If the user's profile is updated within that hour, the client may be showing outdated profile information until it refreshes the token.
You can force the refresh of a token by:
Signing the user out and in again.
Calling User.reload or User.getIdToken(true).
Both of these cases force the client to refresh the ID token, and thus get the latest profile from the servers.
try this.
function handgleRegister() {
auth()
.createUserWithEmailAndPassword(email, password)
.then(userCred => {
userCred.user.updateProfile({
displayName: name,
}).then(()=>{
setUser(auth().currentUser());
};
})
.catch(e => {
...
...
});
}
here's my signup code. I'm just update the profile with the email address right now since i don't have another input for display name. I'm also using redux toolkit.
import React, { Component, useEffect } from "react";
import { View } from "react-native";
import { Button, Input } from "react-native-elements";
import Icon from "react-native-vector-icons/FontAwesome";
import { Dimensions } from "react-native";
import auth from "#react-native-firebase/auth";
import { useDispatch, useSelector } from "react-redux";
import {
clearLoginInfo,
updateLoginInfo,
signInWithEmailAndPassword,
} from "../login/LoginSlice";
export default function SignupScreen(props) {
const { navigation } = props;
const [username, setUsername] = React.useState("");
const [password, setPassword] = React.useState("");
const [passwordErrorMsg, setPasswordErrorMsg] = React.useState("");
const [usernameErrorMsg, setUsernameErrorMsg] = React.useState("");
const [securedText, setSecuredTtext] = React.useState(true);
const dispatch = useDispatch();
function onAuthStateChanged(user) {
console.log("on user change", user);
}
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
return subscriber; // unsubscribe on unmount
}, []);
const signIn = (e) => {
auth()
.createUserWithEmailAndPassword(e.username, e.password)
.then((user) => {
console.log("user = ", user);
user.user
.updateProfile({
displayName: e.username,
photoURL: "abc.com",
})
.then(() => {
const currentUser = auth().currentUser;
console.log("current user ", auth().currentUser);
dispatch(
updateLoginInfo({
displayName: currentUser.displayName,
photoURL: currentUser.photoURL,
})
);
});
})
.catch((error) => {
if (error.code === "auth/email-already-in-use") {
setUsernameErrorMsg("That email address is already in use!");
}
if (error.code === "auth/invalid-email") {
setUsernameErrorMsg("That email address is invalid!");
}
if (error.code === "auth/weak-password") {
setPasswordErrorMsg("please choose a stronger password");
}
console.error(error);
});
};
const handlePasswordChange = (val) => {
setPassword(val);
};
const handleUserNameChange = (val) => {
setUsername(val);
};
const doSignin = () => {
signIn({ username, password });
};
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignContent: "center",
alignItems: "center",
}}
>
<Input
placeholder="Email"
errorMessage={usernameErrorMsg}
value={username}
leftIcon={{ type: "font-awesome", name: "envelope" }}
onChangeText={handleUserNameChange}
/>
<Input
placeholder="Password"
errorMessage={passwordErrorMsg}
errorStyle={{ color: "red" }}
value={password}
leftIcon={<Icon name="lock" size={40} color="black" />}
rightIcon={
securedText ? (
<Icon
name="eye"
size={32}
onPress={() => setSecuredTtext(!securedText)}
color="black"
/>
) : (
<Icon
name="eye-slash"
size={32}
onPress={() => setSecuredTtext(!securedText)}
color="black"
/>
)
}
onChangeText={handlePasswordChange}
secureTextEntry={securedText}
/>
<Button
title="Sign up"
onPress={() => doSignin()}
buttonStyle={{ backgroundColor: "#eda621" }}
style={{ width: Dimensions.get("window").width * 0.5 }}
/>
<Button
title="Back to Sign in"
style={{ width: Dimensions.get("window").width * 0.5, marginTop: 10 }}
onPress={() => navigation.navigate("Signin")}
/>
</View>
);
}
listener:
useEffect(()=>{
if (user != null && user.displayName != '') {
navigation.navigate("Home");
},
[user]});

Categories

Resources