skip to Main Content

What I want to do here is to check if the email provided is valid or not, and then notify user based on this email validation.

Code:

const RightUI = () => {
  const [email, setEmail] = useState("");
  const [isValidEmail, setIsValidEmail] = useState(undefined);

  const handleFormSubmit = (e) => {
    e.preventDefault();
    
    const isValid =
      /^((([!#$%&'*+-/=?^_`{|}~w])|([!#$%&'*+-/=?^_`{|}~w][!#$%&'*+-/=?^_`{|}~.w]{0,}[!#$%&'*+-/=?^_`{|}~w]))[@]w+([-.]w+)*.w+([-.]w+)*)$/gm.test(
        email
      );

    setIsValidEmail(isValid);
    
  };

  useEffect(() => {
    console.log(isValidEmail)
    if (isValidEmail) {
      setTimeout(() => {
        window.location = "https://google.com";
      }, 2500);
    }
  }, [isValidEmail]);

  return (
    <div id="right__ui">
      <div className="right__ui-container">
        <h3>Sign up for exclusive access.</h3>
        <form onSubmit={handleFormSubmit}>
          <input
            type="text"
            placeholder="Your email address"
            id="email_input"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <button type="submit">Get Started</button>
        </form>
        {isValidEmail === undefined ? null : (
          <NotifyUser
            msg={
              isValidEmail
                ? "Thanks for providing your details."
                : "Please provide a valid Email address!"
            }
            type={isValidEmail ? "success" : "error"}
            timeout={3000}
          />
        )}
      </div>
    </div>
  );
};

NotifyUser.js

import { useState, useEffect } from "react";
import "./notifyUser.css";

const NotifyUser = ({ msg, type, timeout }) => {
  const [isVisible, setIsVisible] = useState(true);
  
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsVisible(false);
    }, timeout);

    return () => {
      clearTimeout(timer);
    };
  }, [timeout]);

  const notificationStyle = {
    backgroundColor: notification[type][0],
    color: notification[type][1],
  };

  return (
    <>
      {isVisible && (
        <div
          className="notification-box"
          role="alert"
          style={notificationStyle}
        >
          {msg}
        </div>
      )}
    </>
  );
};

const notification = {
  error: ["#ecc8c5", "#ab3331"],
  success: ["#d4edda", "#155724"],
  info: ["#cce5ff", "#004085"],
};

export default NotifyUser;

The Problem: NotifyUser component renders the very first time (based on the email validation), but after that it does not render. I am new to React, and this part of my learning project, I understand that I am doing something fundamentally wrong here due to lack of my knowledge. Please enlighten me.

2

Answers


  1. I guess the problem is that you conditionally render the component by making the ternary expression isValidEmail === undefined ? null : (... which will only work the first time the email is validated because only the first time the "isValidEmail" equals undefined since it’s the initial state but after if the email is not valid the "isValidEmail" will be false not undefined
    so the problem is you checking against the wrong falsy value
    you should make the condition as
    isValidEmail && (component code here) and better to set the initial value of isValidEmail as false in the useState above
    and this should make the rendering part work not only on the first time

    Login or Signup to reply.
  2. The issue is that when you are sending data to the NotifyUser the first time when its state, isValidEmail is undefined. So, when it becomes truthy the component NotifyUser gets loaded, hence mounted.

    Now the second time, when you change the state of isValidEmail or make a click it doesn’t show because the NotifyUser component is already loaded(mounted) but this time the component receives the new props but you are not hooking it to the useEffect here to perform a state update so the update doesn’t happen.

    To fix this you can make use of either of the two approaches, although I would prefer the second one since it minimises the changes to only its own component and doesn’t affect both the components, unlike first.

    Approach 1 :

    reset the isValidEmail back to null/undefined (always use null instead of undefined here and in initial state). Doing this after the timeout the component will get unmounted and then the state change will be taking place. The trick is component mounting and re-mounting, just so if its not clear in this approach manually.

      useEffect(() => {
        console.log(isValidEmail);
        if (isValidEmail) {
          setTimeout(() => {
            window.location = "https://www.google.com";
          }, 5000);
        } else {
          setTimeout(() => setIsValidEmail(undefined), 2500); // reset it back at the end time
        }
      }, [isValidEmail]);
    

    Approach 2 :

    just add the props inside the useEffect of the NotifyUser, which will make sure to re-run the

    // Inside NotifyUser component
      useEffect(() => {
        const timer = setTimeout(() => {
          setIsVisible(false);
        }, timeout);
    
        return () => {
          clearTimeout(timer);
        };
      }, [timeout, msg]); // I added message but you can also add type or whatever prop you need either here or in a separate useEffect
     
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search