The Login function component updates the state when the onChange event is called. The form inputs get their values (value={state.username}) from the state. However, each time I type something into one of the fields, the component re-renders at each character typed, thus causing the form inputs to lose foucus.
I've tried using the React.memo hook but only learned it's only useful when there is a prop change that causes a re-render.
What is it that I'm missing or doing wrong?
Root component
import React, { useEffect, Fragment } from "react";
import ReactDOM from "react-dom";
import webSocketInstance from "../utils/websocket";
import PrivateRoute from "../utils/privateRoute";
import CreateRoom from "./chat/room";
import Login from "./auth/login";
import Signup from "./auth/signup";
import { BrowserRouter, Switch, Route, Link } from "react-router-dom";
export default function App() {
return (
<BrowserRouter>
<div>
<div>
<ul>
<li>
<Link to="/login">Login</Link>
</li>
<li>
<Link to="/signup">Sign Up</Link>
</li>
</ul>
</div>
<Switch>
<Route path="/" exact>
<Index />
</Route>
<Route path="/login">
<Login /> // <---------------------- Routing of Login component
</Route>
<Route path="/signup">
<Signup />
</Route>
<PrivateRoute path="/room">
<CreateRoom />
</PrivateRoute>
</Switch>
</div>
</BrowserRouter>
);
}
function Index() {
return (
<div>
<h2>Home page</h2>
</div>
);
}
Login Component
import React, { useState, memo } from "react";
import { connect } from "react-redux";
import { Link, Redirect, useHistory, useLocation } from "react-router-dom";
import CreateRoom from "../chat/room";
import { signIn } from "../../states/actions/actions";
import Authentication from "../../utils/authentication";
function Login({ user, isAuthenticated, signIn }) {
const [credentials, setCredentials] = useState({ email: "", password: "" });
// React-router navigation hooks
let location = useLocation();
let history = useHistory();
// Extract credentials from state
const { username, password } = credentials;
// On-change handler
const onChange = (event) => {
setCredentials((state) => {
return {
...state,
[event.target.name]: event.target.value,
};
});
};
// on-submit handler
const onSubmit = (event) => {
// Stop page reload
event.preventDefault();
if (username !== "" && password !== "") {
// Send credentials
signIn(username, password);
return;
}
alert("Fields can not be empty");
};
return (
<section
id="auth-container"
className="flex flex-row w-screen h-screen items-center"
>
<div
id="auth-image-column-left"
className="flex flex-col items-center hidden md:block w-full md:w-1/2 xl:w-2/3 h-screen"
>
<div id="intro-container" className="pl-10">
<h1
id="app-name"
className="
text-blue-400
md:text-2xl
font-bold
leading-tight
mt-12
pb-5
"
>
Chatter
</h1>
<h2
id="app-description"
className="text-md font-bold text-white py-2"
>
Chatter helps you connect and collaborate with your team.
</h2>
</div>
<footer className="">
<p className="text-white">
Built with ❤ by{" "}
<a
href="https://romeopeter.com"
target="_blank"
className="text-blue-400"
>
Romeo Peter
</a>
.
</p>
</footer>
</div>
<div
id="auth-login-column-right"
className="
bg-white
w-full
md:max-w-md
lg:max-w-full
md:mx-auto md:mx-0 md:w-1/2
xl:w-1/3
px-6
lg:px-16
xl:px-12
flex
items-center
justify-center
"
>
<div className="w-50 md:w-full h-100" id="login-container">
<div id="intro-container" className="flex flex-col md:hidden">
<h1
id="app-name"
className="
text-center
text-blue-400
text-2xl
font-bold
pb-5
"
>
Chatter
</h1>
<h2
id="app-description"
className="text-md font-bold text-gray-600 p-2"
>
Chatter helps you connect and share with the people in your life.
</h2>
</div>
<form className="mt-6" onSubmit={onSubmit}>
<div>
<label htmlFor="username" className="block text-gray-700">
Username
</label>
<input
type="text"
name="username"
id="username"
required
placeholder="Enter username"
autoFocus
autoComplete="username"
className="
w-full
px-4
py-3
rounded-lg
bg-gray-200
mt-2
border
focus:border-blue-500 focus:bg-white focus:outline-none
"
value={username}
onChange={onChange} <---------------- onChange event on username
/>
</div>
<div className="mt-4">
<label htmlFor="password" className="block text-gray-700">
Password
</label>
<input
type="password"
name="password"
id="password"
required
placeholder="Enter Password"
minLength="6"
autoComplete="current-password"
className="
w-full
px-4
py-3
rounded-lg
bg-gray-200
mt-2
border
focus:border-blue-500 focus:bg-white focus:outline-none
"
value={password}
onChange={onChange} <--------- onChange event on password
/>
</div>
<div
id="form-utility"
className="flex flex-row justify-between mt-2"
>
<div id="remember-login" className="">
<label
htmlFor="remember_me"
className="text-sm font-semibold text-gray-700"
>
Remember me
<input id="remember_me" type="checkbox" className="" />
</label>
</div>
<div id="forgot-login-password" className="">
<a
href="#"
className="
text-sm
font-semibold
text-gray-700
hover:text-blue-700
focus:text-blue-700
"
>
Forgot Password?
</a>
</div>
</div>
<button
type="submit"
id="login"
className="
w-full
block
bg-indigo-500
hover:bg-indigo-400
focus:bg-indigo-400
text-white
font-semibold
rounded-lg
px-4
py-3
mt-6
"
>
Log In
</button>
</form>
<hr className="my-6 border-gray-300 w-full" />
<button
type="button"
className="
w-full
block
bg-white
hover:bg-gray-100
focus:bg-gray-100
text-gray-900
font-semibold
rounded-lg
px-4
py-3
border border-gray-300
"
>
<div className="flex items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
className="w-6 h-6"
viewBox="0 0 48 48"
>
<defs>
<path
id="a"
d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"
/>
</defs>
<clipPath id="b">
<use xlinkHref="#a" overflow="visible" />
</clipPath>
<path clipPath="url(#b)" fill="#FBBC05" d="M0 37V11l17 13z" />
<path
clipPath="url(#b)"
fill="#EA4335"
d="M0 11l17 13 7-6.1L48 14V0H0z"
/>
<path
clipPath="url(#b)"
fill="#34A853"
d="M0 37l30-23 7.9 1L48 0v48H0z"
/>
<path
clipPath="url(#b)"
fill="#4285F4"
d="M48 48L17 24l-4-3 35-10z"
/>
</svg>
<span className="ml-4">Log in with Google</span>
</div>
</button>
<p className="mt-8 mt-8 pb-5">
Need an account?{" "}
<Link
to="/signup"
className="text-blue-500 hover:text-blue-700 font-semibold"
>
Create an account
</Link>
</p>
</div>
</div>
</section>
);
return loginUI;
}
function mapState(state) {
const { user, isAuthenticated } = state.Auth;
return { user, isAuthenticated };
}
export default connect(mapState, { signIn })(Login);