How to prevent react re-render when onChange handler is called?

Viewed 409

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);
0 Answers
Related