ReactJS: Login form with array of users - javascript

I want to create a login form with array data in User.js file (without any backend)
My User.js file looks like this:
const users = [
{
username: 'admin1',
password: 'admin1#1'
},
{
username:'admin2',
password:'admin2#2'
}
];
and my Login.js looks something like this:
import React, { Component, Fragment } from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
password: ""
};
}
changeInputValue(e) {
this.setState({
[e.target.name]: e.target.value
});
}
validationForm() {
let returnData = {
error : false,
msg: ''
}
const {password} = this.state
//Check password
if(password.length < 8) {
returnData = {
error: true,
msg: 'Password must be more than 8 characters'
}
}
return returnData;
}
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if (validation.error) {
alert(validation.msg)
}else if(username === 'admin2' && password === 'admin1#1') {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
render() {
return (
<div className="container" style={{ paddingTop: "5%" }}>
<form
onSubmit={e => {
this.submitForm(e);
}}
>
<div className="form-group">
<input
type="text"
className="form-control"
name="username"
placeholder="Username"
onChange={e => this.changeInputValue(e)}
/>
</div>
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
onChange={e => this.changeInputValue(e)}
/>
</div>
<button value="submit" className="btn btn-primary" onClick={this.postDetails}>
Submit
</button>
</form>
</div>
);
}
}
export default Login;
Above, I don't know how to check username and password from the passed array. Please show an instance of how it is done. And after successful login, how do I switch to another page?Sorry, I'm new to ReactJS so I'm a bit confused, hope you can help.

Import the data from user.js after u exported it from there.
export const UsersData = [
{
username: 'admin1',
password: 'admin1#1'
},
{
username:'admin2',
password:'admin2#2'
}
];
//Login.js
import UsersData from './user.js'
Now do array operation on this array of objects. Now you can convert the data entered by the user to a similar format provided by User.js.
ie: If the user entered username = alphabeta, password = 1234
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var inputData = {
username : e.target.elements.username.value,
password : e.target.elements.password.value
};
if (validation.error) {
alert(validation.msg)
}else if(UsersData.findIndex(inputData)!==-1) {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
Here we uses an array operation called findIndex which returns -1 if it doesn't find the object in the array else it returns the index.
To know more about Array Opreration in JS : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

Not sure if I understand correstly your question but here is how you can check if the duo user and password are in your array :
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
const App = () => {
const users = [
{
username: "admin1",
password: "admin1#1",
},
{
username: "admin2",
password: "admin2#2",
},
];
const handleSubmit = (e) => {
e.preventDefault();
const toCompare = {
username: e.target.elements.username.value,
password: e.target.elements.password.value,
};
// Or just compare properties
if (users.some(u => JSON.stringify(u) === JSON.stringify(toCompare))) {
console.log('User exists in array');
} else {
console.log('User does not exist in array');
}
};
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="username" name="username" />
<input type="text" placeholder="password" name="password" />
<button type="submit">Send</button>
</form>
);
};
render(<App />, document.getElementById('root'));
And here is the repro on Stackblitz

Related

Login Form use ReactJS (without database) with map()?

I want to create a login form with array data:
const users = [
{
username: 'admin1',
password: '12345678'
},
{
username:'admin2',
password:'012345678'
}
];
and Login.js looks something like this:
import React from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
userName: "",
password: ""
};
}
changeInputValue(e) {
this.setState({
[e.target.name]: e.target.value
});
}
validationForm() {
let returnData = {
error : false,
msg: ''
}
const {password} = this.state
//Check password
if(password.length < 8) {
returnData = {
error: true,
msg: 'Password must be more than 8 characters'
}
}
return returnData;
}
submitForm(e) {
e.preventDefault();
const validation = this.validationForm()
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if (validation.error) {
alert(validation.msg)
}else if(username === 'admin1' && password === '12345678') {
alert("Login successful");
}else {
alert("Wrong password or username");
}
}
render() {
return (
<div className="container" style={{ paddingTop: "5%" }}>
<form
onSubmit={e => {
this.submitForm(e);
}}
>
<div className="form-group">
<input
type="text"
className="form-control"
name="username"
placeholder="Username"
onChange={e => this.changeInputValue(e)}
/>
</div>
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
onChange={e => this.changeInputValue(e)}
/>
</div>
<button value="submit" className="btn btn-primary" onClick={this.postDetails}>
Submit
</button>
</form>
</div>
);
}
}
export default Login;
So the above code only check whether the username and password fields entered in the form match the name and password of single record in the array of objects of User.js the above code is working fine. I don't know how to check username and password from the passed array.
I want to use map () to check for username and password. Please show an instance of how it is done. Sorry, I'm new to ReactJS so I'm a bit confused, hope you can help. Thanks
You can use .some() method.
doc: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
Something like this
var username = e.target.elements.username.value;
var password = e.target.elements.password.value;
if(users.some((elem) => elem.username === username && elem.password === password)) {
// when authentication is valid
} else {
// not a valid username / password
}
You can use find
const user = users.find(user => (user.username === username && user.password === password))
if(user){
//correct user
}
if(!user) {
//incorrect
}

Password States are reacting one character late

Im checking to see if the register forms passwords match, and when they do, something changes. but its happening on 1 "onChange" too late. Ex. User enters "DOG" as the password. when the retype it in the 2nd input, "DOG" doesnt work. but it does if they enter another character or delete one character (Ex. "DOGX" or deleting "G" so its "DO")
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import "./register.css";
function RegisterBoard() {
const history = useHistory();
const [register, changeRegister] = useState({
password: false,
repeatPassword: false,
});
const [info, changeInfo] = useState({
password: "",
repeatPassword: "",
});
const changeValue = (e) => {
const { name, value } = e.target;
changeInfo((prev) => {
return {
...prev,
[name]: value,
};
});
};
const input = (e) => {
const target = e.target.dataset.name;
if (target != "repeatPassword") {
changeRegister({
...register,
[target]: true,
});
} else {
if (info.password != info.repeatPassword) {
changeRegister({
...register,
repeatPassword: false,
});
} else {
changeRegister({
...register,
repeatPassword: true,
});
}
}
};
return (
<div className="registration-form">
<form>
<div>
<input
name="password"
data-name="password"
onChange={(e) => {
changeValue(e);
input(e);
}}
className="password"
type="password"
placeholder="ENTER YOUR PASSWORD HERE"
/>
<div className="animated-button">
</div>
</div>
<div>
<input
id="pwd"
name="repeatPassword"
data-name="repeatPassword"
onChange={(e) => {
changeValue(e);
input(e);
}}
className="repeat-password"
type="password"
placeholder="REPEAT YOUR PASSWORD HERE"
/>
</div>
</div>
</form>
</div>
);
}
export default RegisterBoard;
I guess this is because you are calling both 'changeValue' and 'input' functions within the inputs onChange attribute. Since they are firing at the same time, 'input' is not using the most recent value for 'info', because 'changeValue' hasn't set the new state yet.
Either call the input function within a useEffect hook which is dependent on changes to 'info's' state, or use e.target.value instead of info's state within the 'input' function to compare info.password != info.repeatPassword
EDIT: here is the useEffect way, it simplifies it and you can remove your input function completely: https://codesandbox.io/s/jolly-khorana-8s63b?file=/src/App.js
import React, { useState, useEffect } from "react";
import "./styles.css";
function RegisterBoard() {
const [register, changeRegister] = useState({
password: false,
repeatPassword: false
});
const [info, changeInfo] = useState({
password: "",
repeatPassword: ""
});
const changeValue = (e) => {
const { name, value } = e.target;
changeInfo((prev) => {
return {
...prev,
[name]: value
};
});
};
useEffect(() => {
let password = false;
let repeatPassword = false;
if (info.password !== "") {
password = true;
if (info.password === info.repeatPassword) {
repeatPassword = true;
}
}
changeRegister({ password, repeatPassword });
}, [info]);
return (
<div className="registration-form">
<form>
<div>
<input
name="password"
data-name="password"
onChange={changeValue}
className="password"
type="password"
placeholder="ENTER YOUR PASSWORD HERE"
/>
<div className="animated-button"></div>
</div>
<div>
<input
id="pwd"
name="repeatPassword"
data-name="repeatPassword"
onChange={changeValue}
className="repeat-password"
type="password"
placeholder="REPEAT YOUR PASSWORD HERE"
/>
</div>
</form>
<div>{info.password}</div>
<div>{info.repeatPassword}</div>
<div>{register.repeatPassword ? "match" : "don't match"}</div>
</div>
);
}
export default function App() {
return (
<div className="App">
<RegisterBoard />
</div>
);
}
You're definitely going to want to implement a useEffect here to update the UI every time the password & repeatPassword state changes, to ensure that after the last character is typed that you get the full password. Inside the useEffect is where you'll write your conditional logic. What I provided is just a good example...
import React, { useState, useEffect } from "react";
import { useHistory } from "react-router-dom";
import "./register.css";
function RegisterBoard() {
const history = useHistory();
const [password, setPassword] = useState('')
const [repeatPassword, setRepeatPassword] = useState('')
//const [register, changeRegister] = useState(false);
const changeValue = (e) => {
const { name, value } = e.target.value;
const input = (e) => {
const target = e.target.dataset.name;
if (target != "repeatPassword") {
changeRegister({
...register,
[target]: true,
});
} else {
if (info.password != info.repeatPassword) {
changeRegister({
...register,
repeatPassword: false,
});
} else {
changeRegister({
...register,
repeatPassword: true,
});
}
}
};
useEffect(() => {
if((password !== "" && repeatPassword !== "") && (password !==
repeatPassword)){
console.log("PASSWORDS DO NOT MATCH!!!")
}
console.log(password, repeatPassword)
}, [password, repeatPassword])
return (
<div className="registration-form">
<form>
<div>
<input
name="password"
data-name="password"
onChange={(e) => changeValue(e)}
className="password"
type="password"
placeholder="ENTER YOUR PASSWORD HERE"
/>
<div className="animated-button">
</div>
</div>
<div>
<input
id="pwd"
name="repeatPassword"
data-name="repeatPassword"
onChange={(e) => changeValue(e)}
className="repeat-password"
type="password"
placeholder="REPEAT YOUR PASSWORD HERE"
/>
</div>
</div>
</form>
</div>
);
}
export default RegisterBoard;

How do I check if email already exists using MERN

I have a registration view and I'm trying to check whether the email already exists, I've undone the react code so you can get a good idea of the structure.
The emails are set as unique in the schema.
AuthController
const { check, validationResult } = require("express-validator");
const jwt = require("jsonwebtoken");
const passport = require("passport");
require("../passport");
const Users = require("../models/user");
let validations = [
check("email")
.isEmail()
.withMessage("The email you have entered is not valid")
.contains("#")
.withMessage("The email you have entered does not contain an #"),
check("password")
.isLength({ min: 5 })
.withMessage("The password must have at least 5 characters")
];
// Throw error if the key doesn't exist
if (!process.env.JWT_SECRET) {
console.error("Cannot find JWT key");
}
function generateWebToken(user) {
return jwt.sign(user, process.env.JWT_SECRET, {
subject: user.email,
expiresIn: "7d",
algorithm: "HS256"
});
}
/* POST register a user if one doesn't already exist */
module.exports.register = [
...validations,
(req, res) => {
// Get validation errors from the request
const errors = validationResult(req);
// Return the errors
if (!errors.isEmpty()) {
return res.status(422).json({ error: errors.array() });
}
let hashedPassword = Users.hashPassword(req.body.password);
Users.findOne({ email: req.body.email })
.then(function(user) {
if (user) {
return res
.status(400)
.send(`An account with the email ${req.body.email} already exists`);
} else {
Users.create({
email: req.body.email,
password: hashedPassword
})
.then(function(user) {
res.status(201).json(user);
})
.catch(function(err) {
console.error(err);
res.status(500).send(`Error ${err}`);
});
}
})
.catch(function(err) {
console.error(err);
res.status(500).send(`Error ${err}`);
});
}
];
Register.js (react component)
import React, { Component } from "react";
const initalState = {
email: "",
password: "",
emailErr: "",
passwordErr: ""
};
class Register extends Component {
constructor(props) {
super(props);
this.state = {
initalState,
successMsg: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
}
validate = () => {
let emailErr = "";
let passwordErr = "";
// Email validation
if (!this.state.email) {
emailErr = "Please enter an email";
}
// Password validation
if (!this.state.password) {
passwordErr = "Please enter your password";
}
if (emailErr || passwordErr) {
this.setState({ emailErr, passwordErr });
return false;
}
return true;
};
onEmailChange(event) {
this.setState({ email: event.target.value });
}
onPasswordChange(event) {
this.setState({ password: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const isValid = this.validate();
if (isValid) {
fetch("/api/auth/register", {
method: "POST",
body: JSON.stringify(this.state),
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
})
.then(res => res.json())
.then(this.setState({ successMsg: true }), this.setState(initalState));
}
}
render() {
return (
<>
<div className='block md:flex md:flex-column h-full'>
<div className='p-12 w-full text-center text-gray-800'>
<h1 className='title'>Register</h1>
{this.state.successMsg && (
<div
className='w-full m-auto max-w-lg mb-10 bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative'
role='alert'
>
<strong className='font-bold'>Holy smokes! </strong>
<span className='block sm:inline'>
Account has been created
</span>
</div>
)}
<form className='w-full m-auto max-w-lg'>
<div className='flex flex-wrap -mx-3'>
<div className='w-full px-3 mb-6'>
<label htmlFor='email'>Email Address</label>
<input
id='email'
type='text'
placeholder='johndoe#example.co.uk'
value={this.state.email || ""}
onChange={this.onEmailChange.bind(this)}
/>
<p className='my-2 text-red-500 text-xs'>
{this.state.emailErr}
</p>
</div>
</div>
<div className='flex flex-wrap -mx-3'>
<div className='w-full px-3 mb-6'>
<label htmlFor='password'>Password</label>
<input
id='password'
type='password'
placeholder='*********'
value={this.state.password || ""}
onChange={this.onPasswordChange.bind(this)}
/>
<p className='my-2 text-red-500 text-xs'>
{this.state.passwordErr}
</p>
</div>
</div>
<div className='flex'>
<button
className='btn'
type='button'
onClick={this.handleSubmit.bind(this)}
>
Send
</button>
</div>
</form>
</div>
</div>
</>
);
}
}
export default Register;
Not sure if it's possible just to pass the express validations or what the best solution for this is.
The code above looks fine as this line of code explicitly checks for email duplications in MongoDB
>if (user) {
> return res
> .status(400)
> .send(`An account with the email ${req.body.email} already exists`);
> } else {...
Here is a full solution to display errors from register api (both express-validations and user is already registered error)
I tried to mimic your api and react app, but heavily refactored:
1-) In api we need to convert express validation errors in a readable way:
Normally its validation errors are in an array like this:
{
"error": [
{
"value": "abcdef#net",
"msg": "The email you have entered is not valid",
"param": "email",
"location": "body"
},
{
"value": "12",
"msg": "The password must have at least 5 characters",
"param": "password",
"location": "body"
}
]
}
With the following code, I converted the error messages in this format to easily access in react app by field name:
{
"errors": {
"email": "The email you have entered is not valid",
"password": "The password must have at least 5 characters"
}
}
register route:
const { check, validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const { User } = require("../models/user");
const express = require("express");
const router = express.Router();
let validations = [
check("email")
.isEmail()
.withMessage("The email you have entered is not valid"),
check("password")
.isLength({ min: 5 })
.withMessage("The password must have at least 5 characters")
];
router.post("/register", validations, async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const err = {};
errors.array().forEach(error => {
err[error.param] = error.msg;
});
return res.status(422).json({ errors: err });
}
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (user) return res.status(400).send("User already registered.");
user = new User({ email, password });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
user = await user.save();
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
module.exports = router;
In the react side I used axios instead of fetch since the error handling is far easier with axios:
import React, { Component } from "react";
import axios from "axios";
class App extends Component {
state = {
email: "",
password: "",
fieldErrors: {},
registerError: null
};
handleSubmit = async e => {
e.preventDefault();
this.setState({
fieldErrors: {},
registerError: null
})
const { email, password } = this.state;
try {
const response = await axios.post(
"https://express-validator-auth.herokuapp.com/api/users/register",
{ email, password }
);
console.log(response.data);
alert("Registered");
} catch (error) {
if (error.response && error.response.data) {
if (error.response.data.errors) {
this.setState({
fieldErrors: error.response.data.errors
});
} else {
this.setState({
registerError: error.response.data
});
}
} else {
console.log(error);
}
}
};
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
render() {
const { email, password, fieldErrors, registerError } = this.state;
return (
<div>
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label>Email</label>
<input
type="text"
className={
!fieldErrors.email ? "form-control" : "form-control is-invalid"
}
name="email"
value={email}
onChange={this.handleChange}
/>
{fieldErrors.email && (
<div className="invalid-feedback">{fieldErrors.email}</div>
)}
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className={
!fieldErrors.password
? "form-control"
: "form-control is-invalid"
}
name="password"
value={password}
onChange={this.handleChange}
/>
{fieldErrors.password && (
<div className="invalid-feedback">{fieldErrors.password}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
{registerError && (
<div className="alert alert-danger" role="alert">
{registerError}
</div>
)}
</form>
<br />
{JSON.stringify(this.state)}
</div>
);
}
}
export default App;
So when an validation error occurres form will look like this:
And when the "user is already registered error" occurres form validation will look like this:
The react app can be accessed from this codesandbox:
https://codesandbox.io/s/gracious-mccarthy-kluor

Switching input field form validation in react

Currently, in my form, the input fields get validated as soon as the user types in something. Here's the code for that-
index.js
import React from "react";
import ReactDOM from "react-dom";
import ShowError from "./ShowError";
import "./styles.css";
class App extends React.Component {
state = {
email: "",
name: "",
mobile: "",
errors: {
email: "",
name: "",
mobile: ""
},
nameError: false,
emailError: false,
mobileError: false,
formError: false
};
showMsg = () => {
if (!this.state.formError) {
alert("Error");
}
};
validateFunc = (name, value) => {
let error = this.state.errors;
let nameError = this.state.nameError;
let emailError = this.state.emailError;
let mobileError = this.state.mobileError;
switch (name) {
case "name":
nameError = !/^[a-zA-Z ]+$/.test(value);
error.name = nameError ? " is Invalid" : "";
break;
case "email":
emailError = !/^([\w.%+-]+)#([\w-]+\.)+([\w]{2,})$/i.test(value);
error.email = emailError ? " is Invalid" : "";
break;
case "mobile":
mobileError = !/^[0-9]{10}$/.test(value);
error.mobile = mobileError ? " is Invalid" : "";
break;
}
this.setState({
errors: error,
nameError: nameError,
emailError: emailError,
mobileError: mobileError
});
};
handleInput = event => {
const name = event.target.name;
const value = event.target.value;
this.setState(
{
[name]: value
},
this.validateFunc(name, value)
);
};
handleSubmit = event => {
event.preventDefault();
let formError =
this.state.nameError || this.state.emailError || this.state.mobileError;
this.setState({
formError: formError
});
};
render() {
return (
<div className="App">
<h1>Basic Form Validation</h1>
<form className="FormStyle">
<input
className="FieldStyle"
type="text"
name="name"
placeholder="Name"
onChange={event => this.handleInput(event)}
/>
<input
className="FieldStyle"
type="email"
name="email"
placeholder="Email"
onChange={event => this.handleInput(event)}
/>
<input
className="FieldStyle"
type="number"
name="mobile"
placeholder="Mobile"
onChange={event => this.handleInput(event)}
/>
<button
className="FieldStyle"
type="submit"
onClick={event => this.handleSubmit(event)}
>
SUBMIT
</button>
</form>
<ShowError error={this.state.errors} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
ShowError.js
import React from "react";
const ShowError = props => {
return Object.keys(props.error).map((field, index) => {
if (props.error[field].length > 0) {
return (
<p key={index}>
{field} {props.error[field]}
</p>
);
} else {
return "";
}
});
};
export default ShowError;
Expected Behaviour- What I want is, the fields should get validated as soon as the user focuses on next input field or when 'tab' key is pressed, I don't want to validate while the user is typing but when the user switches the field. How can I achieve the above behaviour? Thanks a lot!
P.S. - Would be better if I can achieve this without using libraries like redux-forms.
Use onBlur so the event is triggered when the user leaves the component
onBlur={event => this.handleInput(event)}

React onchange event: this.setState() not setting state?

I am trying to set state via this.setState() of username and password when user types a value in username and password field. I am using onChange event type
ISSUE: the state is not changing. I log this.state.data.username in the render().
import React, { Component } from "react";
import { Form, Button } from "react-bootstrap";
import { Link } from "react-router-dom";
var Joi = require("joi-browser");
class Login extends Component {
state = {
data: { username: "a", password: "b " },
errors: {
email: "ddsfds",
password: "aaaa"
}
};
schema = {
username: Joi.string()
.min(0)
.required()
.label("Username"),
password: Joi.string()
.required()
.label("Password")
};
handleSubmit = event => {
event.preventDefault();
console.log("submited.", event.target);
const { data } = this.state;
const { err } = Joi.validate(data, this.schema);
if (err) {
console.log("error is true", err);
} else {
console.log("not true");
}
};
handleEmailOnChange = event => {
const inputUsername = event.target.value;
console.log("input is...", inputUsername);
this.setState({ username: inputUsername });
};
handlePassword = event => {
const passwordInput = event.target.value;
this.setState({ password: passwordInput });
};
render() {
console.log("username ", this.state.data.username);
return (
<div id="form-wrapper">
<Form>
<Form.Group controlId="formBasicEmail">
<h4>Sign In</h4>
<Form.Control
type="email"
placeholder="Enter email"
onChange={this.handleEmailOnChange}
/>
{/* <span>{this.state.errors.username} </span> */}
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Control
type="password"
placeholder="Password"
onChange={this.handlePassword}
/>
</Form.Group>
<div id="register-wrapper">
<Link to="/register" type="button" className="btn btn-warning">
Register Account
</Link>
<Button
variant="primary"
className="m-2"
type="submit"
onClick={this.handleSubmit}
>
Submit
</Button>
</div>
</Form>
</div>
);
}
}
export default Login;
You aren't updating the state correctly or not using it correctly. The state in your constructor has data object with username and password
handleEmailOnChange = event => {
const inputUsername = event.target.value;
console.log("input is...", inputUsername);
this.setState(prev => ({data: {...prev.data, username: inputUsername } }));
};
handlePassword = event => {
const passwordInput = event.target.value;
this.setState(prev => ({data: {...prev.data, password: passwordInput } }));
};
The state you are changing is this.state.username, the one you console is this.state.data.username.
To set data in your state, use:
this.setState(prevState => ({
data: {
username: inputUsername,
...prevState.data
}
})

Categories