skip to Main Content

I am having an issue understanding why my react component is throwing an error with my form. If I hit enter it does not work as expected as in it does nothing. If I click it will work but it will spam error out until I refresh with this error:

Expected onClick listener to be a function, instead got a value of string type.

Now that being said here is my form and then entire file:

<div className="form-group">
          <form onSubmit={()=>onSubmit()}>
            <input type="submit" className="form-control" />
          </form>
        </div>



import React from "react";
import { FaSignInAlt } from "react-icons/fa";
import { ToastContainer } from "react-toastify";
import 'react-toastify/dist/ReactToastify.css';
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { toast } from "react-toastify";
import { login, reset } from "../features/authSlice";
import Spinner from "../Components/Spinner";

const Login = () => {
  const [formData, setFormData] = useState({
    alias: "",
    password: "",
  });

  const { alias, password } = formData;
  const navigate = useNavigate();
  const dispatch = useDispatch();

  const { user, isLoading, isError, isSuccess, message } = useSelector(
    (state) => state.auth
  );

  useEffect(() => {
    if (isError) {
      toast.error(message)
    }

    if (isSuccess || user) {
      navigate('/')
    }

    dispatch(reset())
  }, [user, isError, isSuccess, message, navigate, dispatch])


  const handleOnChange = (e) => {
    setFormData((prevState) => ({
      ...prevState,
      [e.target.name]: e.target.value,
    }));
  };
  const onSubmit = (e) => {
    const userData = {
      alias,
      password,
    };

    dispatch(login(userData));
  };

  if (isLoading) {
    return <Spinner />
  }

  return (
    <div>
      <section className="heading">
        <h1>
          <FaSignInAlt /> Login
        </h1>
        <p>Please login</p>
      </section>
      <section>
        <div className="form-group">
          <form>
            <input
              type="text"
              className="form-control"
              id="alias"
              name="alias"
              value={alias}
              placeholder="enter your alias"
              onChange={handleOnChange}
            />
          </form>
        </div>
        <div className="form-group">
          <form>
            <input
              type="text"
              className="form-control"
              id="password"
              name="password"
              value={password}
              placeholder="enter your password"
              onChange={handleOnChange}
            />
          </form>
        </div>
        <div className="form-group">
          <form onSubmit={()=>onSubmit()}>
            <input type="submit" className="form-control" />
          </form>
        </div>
      </section>
    </div>
  );
};

export default Login;

I tried switching the onSubmit to onClick and removing the lambda function in the {} braces

3

Answers


  1. There is no reason for you to have this error in the code you are showing, but your form is incorrect. You might need to remove the form tag around your inputs. Only one is necessary, wrapping your whole form.

    If it does not resolve your problem, please try to provide a repro on stackblitz or codesandbox so we can check it out.

    Login or Signup to reply.
  2. You created multiple forms in your example and then submitted only the last one. (If you really wanted to do this, you would need to do some more programming.)

    To resolve your issue, you need to fix two bugs:

    1. The onSubmit function should prevent the default form submission behavior by adding e.preventDefault();.
    const onSubmit = (e) => {
      e.preventDefault();
      const userData = {
        alias,
        password,
      };
    
      dispatch(login(userData));
    };
    1. The form-groups should be wrapped by a single form element with the onSubmit property. (You don’t need to wrap the onSubmit in an arrow function there.)
    return (
      <div>
        <section className="heading">
          <h1>
            <FaSignInAlt /> Login
          </h1>
          <p>Please login</p>
        </section>
        <section>
          <form onSubmit={onSubmit}>
            <div className="form-group">
              <input
                type="text"
                className="form-control"
                id="alias"
                name="alias"
                value={alias}
                placeholder="enter your alias"
                onChange={handleOnChange}
              />
            </div>
            <div className="form-group">
              <input
                type="password"
                className="form-control"
                id="password"
                name="password"
                value={password}
                placeholder="enter your password"
                onChange={handleOnChange}
              />
            </div>
            <div className="form-group">
              <input type="submit" className="form-control" />
            </div>
          </form>
        </section>
      </div>
    );

    Because the button has the type "submit", it calls automatically the form’s onSubmit function. You can read more about forms and submitting in the new react documentation.

    Login or Signup to reply.
  3. Why are all your form elements in different form tags? If it is for styling purposes, you can instead put them in divs and then style them using classes, but if you want to handle the submit of the form with the elements in them, then you can do something like this

    <form onSubmit={(e)=>onSubmit(e)}>
      <div class="form-group">
        <input
          type="text"
          className="form-control"
          id="alias"
          name="alias"
          value="{alias}"
          placeholder="enter your alias"
          onChange="{handleOnChange}"
        />
      </div>
      <div className="form-group">
        <input
          type="text"
          className="form-control"
          id="password"
          name="password"
          value="{password}"
          placeholder="enter your password"
          onChange="{handleOnChange}"
        />
      </div>
      <div className="form-group">
        <input type="submit" className="form-control" />
      </div>
    </form>
    

    Also, you recieved the event e in your function but you didn’t pass it in your callback function.

    <form onSubmit={(e)=>onSubmit(e)}>
    

    You can instead just pass the function without calling it and the event will be passed automatically:

    <form onSubmit={onSubmit}>
    

    Note: You can also use onClick but instead of having the <input type="submit" className="form-control" />, you can rather have a <button class="form-control" onClick={onSubmit}></button> and hence, the onSubmit attribute can be removed from the <form>‘s opening tag

    By the way, you can try naming your submit function something like handleSubmit instead of onSubmit to avoid confusion 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search