How to display data from an API in react js? - reactjs

Here I have a login form that I created in react js. The API I'm using gives a response as "Successful Login" or "Authentication Failed. Unable to login" depending on whether the login credentials match or not. In the login form I'm using a react hook and axios.post to send the "name" and "password" to the API. How can I also print the response I'm getting back from the API?
Here is the Login.js component:
import React, { Component } from "react";
import { useState, useEffect } from "react";
import axios from "axios";
import { Button, TextField } from "#mui/material";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
password: "",
};
}
changeHandler = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
submitHandler = (e) => {
e.preventDefault();
console.log(this.state);
axios
.post("http://localhost:8080/users/login", this.state)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};
render() {
const { name, password } = this.state;
return (
<div>
<h1>Login Page</h1>
<form onSubmit={this.submitHandler}>
<TextField
name="name"
label="Enter Username"
color="secondary"
focused
size="small"
variant="outlined"
onChange={this.changeHandler}
id="name"
value={name}
type="text"
placeholder="Username"
className="form-control"
/>
<p />
<TextField
name="password"
label="Enter Password"
color="secondary"
focused
size="small"
variant="outlined"
onChange={this.changeHandler}
id="password"
value={password}
type="text"
placeholder="Password"
className="form-control"
/>
<p />
<Button type="submit" variant="contained">
Login
</Button>
</form>
</div>
);
}
}
export default Login;
And here is what the console shows:
{name: 'Mike', password: 'password1234'}
{data: 'Authentication Failed. Unable to login', status: 200, statusText: '', headers: AxiosHeaders, config: {…}, …}
{name: 'Mike', password: 'Pass1234'}
{data: 'Successful Login', status: 200, statusText: '', headers: AxiosHeaders, config: {…}, …}
Can I use another react hook to fetch the data? The API uses POST method so I'm not sure how to do that.

here is a very basic example of login page using hooks. In the login function, you should call the API you want and use the setResponse to display the response on the screen
const [Name, setName] = useState("");
const [Pass, setPass] = useState("");
const [Response, setResponse] = useState("");
const userChange = (event) => {
setName(event.target.value);
};
const passChange = (event) => {
setPass(event.target.value);
};
const login = () => {
// login using Name and Pass
setResponse("server response")
}
return (
<ThemeComponent>
<TextField label={"user"} onchange={userChange} />
<TextField label={"pass"} onchange={passChange} />
{Response}
<Button onClick={login} text="LOGIN">LOGIN</Button>
</ThemeComponent>
)

Related

handleSubmit to call another function with event parameter

This is React JS.
I had a nice working sendData function that creates a new record on my json file.
It worked nice until I decided to add useForm to add some yup resolvers.
Now in the <form> tag here is onSubmit={}.
If I write here
<form onSubmit={handleSubmit(sendData(), onSubmit)}>, I get the error and nothing works as before.
enter image description here
I except to understand how handleSubmit works and how to resolve this problem.
Thanks in advance, guys!
my code:
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { Link, useNavigate } from 'react-router-dom';
import Confirmation from './Confirmation';
import * as yup from 'yup';
import { yupResolver } from '#hookform/resolvers/yup';
const schema = yup.object().shape({
name: yup.string().required(),
age: yup.number().positive().required(),
salary: yup.number().positive().required(),
email: yup.string().required(),
})
.required();
export default function LogIn() {
const { register, handleSubmit, formState: { errors }, } = useForm({
resolver: yupResolver(schema),
});
// for redirection
let navigate = useNavigate();
// modal for ghost mode
const [show, setShow] = useState(false);
const [details, setDetails] = useState({
name: '',
age: 0,
salary: 0,
email: ''
})
const sendData = async (event) => {
event.preventDefault()
const {name, age, salary, email} = details;
const res = await fetch("i hide the link :D",
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name, age, salary, email
})
})
navigate("/main");
}
const onSubmit = (data) => {
console.log(data)
}
return (
<div>
{show && <Confirmation show={show} setShow={setShow} />}
<div className="form-center">
<h1>Few Information</h1>
<form onSubmit={handleSubmit(sendData(), onSubmit)}>
<div className="form-controll">
<input type="text" {...register('name')} placeholder="Name"
onChange={(e) => setDetails({...details,name:e.target.value})}/>
{errors.name?.message && <p>{errors.name?.message}</p>}
<input type="number" {...register('age')} placeholder="Age"
onChange={(e) => setDetails({...details,age:e.target.value})}/>
{errors.age?.message && <p>{errors.age?.message}</p>}
<input type="number" {...register('salary')} placeholder="Salary in $"
onChange={(e) => setDetails({...details,salary:e.target.value})}/>
{errors.salary?.message && <p>{errors.salary?.message}</p>}
<input type="email" {...register('email')} placeholder="Email"
onChange={(e) => setDetails({...details,email:e.target.value})}/>
{errors.email?.message && <p>{errors.email?.message}</p>}
</div>
<div className="forgot">
Don't want to share data?<br></br>
<button onClick={() => {setShow(true)}}>Ghost mode</button>
</div>
<div className="btn">
<input type='submit' value='Go' />
</div>
</form>
</div>
</div>
)
}
handleSubmit function is a wrapper for react-hook-form to manage your data inputs, validation, errors, etc.. before calling your own sendData function.
Consider doing:
export default function LogIn() {
const sendData = async (data) => {
const {name} = data;
// your post request
}
return (
<form onSubmit={handleSubmit(sendData}> // remove the useless onSubmit
<input
type="text"
{...register('name')}
placeholder="Name"
// remove the onChange prop
/>
</form>
)
}

my form won't refresh back to initial state or navigate to the feeds page after success full registration i'm i wrong using async?

my form won't refresh back to initial state or navigate to the feeds page after success full registration and now react is telling me Async await is only available in es8 please can i go about this i want the form to provide some kind of feedback after registration like to n avigate to the homepage and clear all field but it's not working
import { Link, useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify'
import {
getAuth,
createUserWithEmailAndPassword,
updateProfile,
} from 'firebase/auth'
import { setDoc, doc, serverTimestamp } from 'firebase/firestore'
import { db } from '../firebase.config'
import OAuth from '../components/OAuth'
function SignUp() {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
})
const { name, email, password } = formData
const navigate = useNavigate()
const onChange = (e) => {
setFormData((prevState) => ({
...prevState,
[e.target.id]: e.target.value,
}))
}
const onSubmit = async (e) => {
e.preventDefault()
try {
const auth = getAuth()
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
)
const user = userCredential.user
updateProfile(auth.currentUser, {
displayName: name,
})
const formDataCopy = { ...formData }
delete formDataCopy.password
formDataCopy.timestamp = serverTimestamp()
await setDoc(doc(db, 'users', user.uid), formDataCopy)
navigate('/')
} catch (error) {
toast.error('Something went wrong with registration')
}
}
return (
<>
<div className='pageContainer'>
<header>
<p className='pageHeader'>Welcome Back!</p>
</header>
<form onSubmit={onSubmit}>
<input
type='text'
className='nameInput'
placeholder='Name'
id='name'
value={name}
onChange={onChange}
/>
<input
type='email'
className='emailInput'
placeholder='Email'
id='email'
value={email}
onChange={onChange}
/>
<div className='passwordInputDiv'>
<input
type='password'
className='passwordInput'
placeholder='Password'
id='password'
value={password}
onChange={onChange}
/>
</div>
<Link to='/forgot-password' className='forgotPasswordLink'>
Forgot Password
</Link>
<div className='signUpBar'>
<p className='signUpText'>Sign Up</p>
<button className='signUpButton'>
Sign Up
</button>
</div>
</form>
<OAuth />
<Link to='/sign-in' className='registerLink'>
Sign In Instead
</Link>
</div>
</>
)
}
export default SignUp

next-auth custom signIn form don't pass username and password to [...nextauth].js

I wanna use custom signin page for next-auth
problem is that I can not pass data from signin page to [...nextauth].js .
signIn('credentials', { redirect: false, phone: phone, password: password })
can access to provider in [..nextauth].js , but
Providers.Credentials({... didn't run for getting token from API .
1.[...nextauth].js
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import axios from 'axios'
import { useRouter } from 'next/router'
const providers = [
Providers.Credentials({
id: 'credentials',
name: 'credentials',
authorize: async (credentials) => {
const user = await axios.post('MyAPI',
{
phone: credentials.phone,
password: credentials.password
},
)
}
})
]
const callbacks = {
// Getting the JWT token from API response
async session(session, user) {
session.accessToken = user.token
return session
}
}
const options = {
providers,
callbacks
}
export default (req, res) => NextAuth(req, res, options)
2.signin.js
import { useState } from "react";
import { signIn, csrfToken } from 'next-auth/client';
export default function Login() {
const [phone, setPhone] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = async (e) => {
// e.preventDefault();
await signIn('credentials', { redirect: false, phone: phone, password: password })
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Phone</label>
<input
id="username"
name="username"
type="text"
placeholder="Phone"
onChange={(e) => setPhone(e.target.value)}
value={phone}
/>
</div>
<div>
<label>Password</label>
<input
id="password"
name="password"
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
value={password}
/>
</div>
<button type="submit">
Login
</button>
</form>
);
}
in your [...nextauth].js, you need to specify the credentials:
...
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" }
}
...
Follow the docs https://next-auth.js.org/providers/credentials
A suggestion:
if your backend is self-hosted, why not to query your db directly as [...nextauth].js runs on the backend?

The React Application does not work as intended when submitting a form

I created a register page for my web Application using React. Here is my Code for Register Component -
import React, { useState } from 'react';
import { Avatar, Button, Paper, Grid, Typography, Container } from '#material-ui/core';
import axios from "axios";
import useStyles from './styles';
import Input from './Input';
const initialState = { name: '', email: '', password: '', mobile: '', confirmPassword: '' };
const Register = () => {
const [form, setForm] = useState(initialState);
const classes = useStyles();
const handleSubmit = async () => {
const { data } = await axios.post('http://localhost:4000/users/register', initialState);
console.log(data);
};
const handleChange = (e) => setForm({ ...form, [e.target.name]: e.target.value });
return (
<div>
<Container component="main" maxWidth="xs">
<Paper className={classes.paper} elevation={3}>
<Typography component="h1" variant="h5">Sign up</Typography>
<form className={classes.form} onSubmit={handleSubmit}>
<Grid container spacing={2}>
<Input name="name" label="Full Name" handleChange={handleChange} autoFocus/>
<Input name="mobile" label="Mobile Number" handleChange={handleChange}/>
<Input name="email" label="Email Address" handleChange={handleChange} type="email"/>
<Input name="password" label="Password" handleChange={handleChange} type='password'/>
<Input name="confirmPassword" label="Confirm Password" handleChange={handleChange} type="password"/>
</Grid>
<Button type="submit" fullWidth variant="contained" color="primary" className={classes.submit}>
Sign Up
</Button>
</form>
</Paper>
</Container>
</div>
);
};
export default Register;
When a form is submitted, no request is made on the server side. Instead, it redirects to the same page again with query parameters equal to the input bodies of the form. What am I doing wrong here?
You aren't preventing the default action of the form. Since you are using a standard html form, submitting it will just default to a get request which would include the values in the url like you have said.
Preventing the default will allow you to then do a non default action like the axios call you want.
const handleSubmit = async (e) => {
e.preventDefault()
const { data } = await axios.post('http://localhost:4000/users/register', initialState);
console.log(data);
};
Use event.preventDefault() in handelSubmit as it will stop the default action of the browser which is reloading on submititing a a form.
const handleSubmit = async (event) => {
event.preventDefault();
// other line of code
};

Submitting form returns proxy object instead of form data in Reactjs

I am creating a login form using semantic-ui in Reactjs. Please find the code below:
The the login form itself:
import React from 'react';
import { Form, Button } from 'semantic-ui-react';
const LoginPage = ({ email, password, handleChange, handleSubmit, errors }) => (
<Form onSubmit={handleSubmit}>
<Form.Field>
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
id="email"
placeholder="example#example.com"
value={email}
onChange={(e) => handleChange(e)}
/>
</Form.Field>
<Form.Field>
<label htmlFor="password">Password:</label>
<input
type="password"
name="password"
id="password"
value={password}
onChange={(e) => handleChange(e)}
/>
</Form.Field>
<Button primary> Login </Button>
</Form>
);
export default LoginPage;
The login container (parent component) is as below:
import React, { Component } from 'react';
import { LoginPage } from '../components';
import Validator from 'validator';
class Login extends Component {
constructor(props) {
super(props)
this.state = {
data: {
email: '',
password: ''
},
loading: false,
errors: {}
}
}
handleChange = (e) => {
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
}
handleSubmit = (values) => {
console.log(values);
const errors = this.validate(this.state.data);
this.setState({
errors: errors
})
}
validate = (data) => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid Email";
if (!data.password) errors.password = "Password cannot be blank";
return errors;
}
render() {
return (
<LoginPage
email={this.state.data.email}
password={this.state.data.password}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
errors={this.state.errors}
/>
)
}
}
export default Login;
When I try to console log values in the handleSubmit function of the parent component it always returns proxy object instead of form values or form data.
Proxy {dispatchConfig: {…}, _targetInst: ReactDOMComponent, isDefaultPrevented: ƒ, isPropagationStopped: ƒ, _dispatchListeners: ƒ, …}
Could anyone let me know where am I going wrong ?
Thanks
The "Proxy" object seems to be an Event object. Indeed the semantic-ui docs say
Our handles data just like a vanilla React . See React's controlled components docs for more.
and here is the vanilla react example it refers to:
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
So with this library it is your own duty to retrieve the form data from your state/store, it is not passed to onSubmit automatically.
handleSubmit = (e) => {
console.log(e);
const errors = this.validate(this.state.data);
this.setState({
errors: errors
})
}
So actually it is correct as you have it, because you are not using this parameter e/values anywhere. You were only confused by the log and your variable name. You could simply omit it.

Resources