0
votes

Hello everyone I have this error while I am trying to validate the input component on React/NextJS.

Unhandled Runtime Error TypeError: Cannot read property 'value' of undefined

Source:

.next\static\chunks\pages\index.js (76:33) @ SignUp

  74 | name="username"
  75 | label="Nombre completo:"
> 76 | defaultValue={error.user.value}
     |                         ^
  77 | disabled={isLoading}
  78 | ref={username}
  79 | message={error.user.msg}

This is my Input component:

import React, { Component } from "react";
import { IoMdCheckmark } from "react-icons/io";
import { IoCloseSharp } from "react-icons/io5";

const Input = React.forwardRef((props, ref) => {
  class Input extends Component {
    render() {
      return (
        <div className={`input ${props.variant}`}>
          <div className="label">{props.label}</div>
          {props.variant === "warning" ? (
            <div
              className={`icon ${props.variant} bg-${props.variant} text-center rounded-full text-1xl p-px mt-5 mr-3`}
            >
              <IoCloseSharp />
            </div>
          ) : null}
          {props.variant === "success" ? (
            <div
              className={`icon ${props.variant} bg-${props.variant} text-center rounded-full text-1xl p-px mt-5 mr-3`}
            >
              <IoMdCheckmark />
            </div>
          ) : null}
          <input
            type={props.type}
            id={props.id}
            defaultValue={props.defaultValue}
            name={props.name}
            placeholder={props.placeholder}
            ref={ref}
            disabled={props.disabled}
          />
          <div className="message">
            {props.message === "" || props.message === undefined ? (
              <>&nbsp;</>
            ) : (
              props.message
            )}
          </div>
        </div>
      );
    }
  }
  return <Input />;
});

export default Input;

This is the component where I am trying to validate:

import React, { useState, createRef } from "react";
import Input from "./Input";
import { FaFacebookSquare } from "react-icons/fa";
import { FcGoogle } from "react-icons/fc";
import { BiLogInCircle } from "react-icons/bi";
import { CgSpinner } from "react-icons/cg";

export default function SignUp() {
  const [isLoading, setLoading] = useState(false);
  const [error, setError] = useState({
    user: { error: "", msg: "", value: null },
    email: { error: "", msg: "", value: null },
  });
  const username = createRef();
  const email = createRef();
  const cellphone = createRef();
  const password = createRef();

  const handleLogin = (e) => {
    e.preventDefault();
    setLoading(true);

    // Full-name validation
    if (username.current.value === "") {
      setError({
        user: {
          error: "warning",
          msg: "Ingresa tu nombre completo.",
          value: username.current.value,
        },
      });
      setLoading(false);
    } else {
      setError({
        user: {
          error: "success",
          msg: "Correcto.",
          value: username.current.value,
        },
      });
    }
    // E-mail validation

    if (email.current.value === "" || email.current.value === undefined) {
      setError({
        email: {
          error: "warning",
          msg: "Ingresa tu correo electronico.",
          value: email.current.value,
        },
      });
      setLoading(false);
    } else {
      setError({
        email: {
          error: "success",
          msg: "Correcto.",
          value: email.current.value,
        },
      });
    }

    setTimeout(() => {
      setLoading(false);
    }, 3000);
  };

  return (
    <form onSubmit={(e) => handleLogin(e)}>
      <div className="w-full text-center text-2xl mb-5">Registrate</div>
      <Input
        type="text"
        id="username"
        name="username"
        label="Nombre completo:"
        defaultValue={error.user.value}
        disabled={isLoading}
        ref={username}
        message={error.user.msg}
        variant={error.user.error}
      />
      <Input
        type="text"
        id="email"
        name="email"
        label="Correo electronico:"
        defaultValue={error.email.value}
        disabled={isLoading}
        ref={email}
        message={error.email.msg}
        variant={error.email.error}
      />
      <Input
        type="text"
        id="cellphone"
        name="cellphone"
        label="Numero de celular:"
      />
      <Input
        type="password"
        id="password"
        name="password"
        label="Contraseña:"
      />
      <button
        disabled={isLoading}
        className={`flex flex-row px-3 justify-center items-center border border-black bg-black text-white focus:outline-none w-full rounded-md py-3 text-sm ${
          isLoading && `cursor-not-allowed`
        }`}
      >
        <span className="text-xl">
          <BiLogInCircle />
        </span>
        <span className="flex-1">
          {isLoading ? (
            <CgSpinner className="animate-spin text-xl mx-auto" />
          ) : (
            <div className="text-sm">Registrarme</div>
          )}
        </span>
        <span className="">&nbsp;</span>
      </button>

      <hr className="my-5" />
      <button
        type="button"
        className="flex flex-row px-3 justify-center items-center border border-gray-500 focus:outline-none w-full rounded-md py-3 text-sm"
      >
        <span className="text-xl">
          <FcGoogle />
        </span>
        <span className="flex-1">Registrarme con Google</span>
        <span className="">&nbsp;</span>
      </button>
      <button
        type="button"
        className="flex flex-row px-3 mt-2 justify-center items-center border border-gray-500 focus:outline-none w-full rounded-md py-3 text-sm"
      >
        <span className="text-xl text-blue-400">
          <FaFacebookSquare />
        </span>
        <span className="flex-1">Registrarme con Facebook</span>
        <span className="">&nbsp;</span>
      </button>
    </form>
  );
}

When I try to perform the submit, it send me the error. Any idea what I am doing wrong? Thank you :)

1
It might be while render, please try to use optional chain ` defaultValue={error?.user?.value}`Uladz Kha
setError does not merge fields, when setting email, you erase userNadia Chibrikova
@NadiaChibrikova thank you, I solved the problem changing how I was updating the setError => setError((prevState) => ({ ...prevState, user: { error: "warning", msg: "Ingresa tu nombre completo.", value: username.current.value, }, }));Riddle
Cool, glad it helped :)Nadia Chibrikova

1 Answers

0
votes

@NadiaChibrikova, thank you for found my the error.

I changed the method I was updating the state.

Wrong: I was erasing the state.

setError({user: {
          error: "warning",
          msg: "Ingresa tu nombre completo.",
          value: username.current.value,
        }); 

Correct: Updating the prevState.

setError((prevState) => ({
        ...prevState,
        user: {
          error: "warning",
          msg: "Ingresa tu nombre completo.",
          value: username.current.value,
        },
      }));