reactjsonclickdom-eventsonchangeonblur

onBlur, onChange, onClick on react is triggering twice


I am trying to build a form with react. But every onBlur, onChange, and onClick is triggering twice. It happens if i try to console log inside the reducer function. The JSX is -

import React, { useReducer } from "react";

const LongForm = () => {
  const initialState = {
    firstName: "",
    lastName: "",
    email: "",
    gender: "",
    education: "",
    quantity: 0,
    feedback: "",
    term: false,
  };

  const reducer = (state, action) => {
    switch (action.type) {
      case "INPUT": {
        return {
          ...state,
          [action.payload.name]: action.payload.value,
        };
      }
      case "TOGGLE": {
        return {
          ...state,
          term: !state.term,
        };
      }
      default:
        return state;
    }
  };

  const [state, dispatch] = useReducer(reducer, initialState);

  const submit = (event) => {
    event.preventDefault();
  };

  return (
    <div>
      <form
        onSubmit={submit}
      >
        <div>
          <label htmlFor="firstName">
            First Name
          </label>
          <input
            type="text"
            name="firstName"
            id="firstName"

            // prints twice
            onBlur={(e) => {
              dispatch({
                type: "INPUT",
                payload: {
                  name: e.target.name,
                  value: e.target.value,
                },
              });
            }}
          />
        </div>
        <div>
          <label htmlFor="lastName">
            Last Name
          </label>
          <input
            type="text"
            name="lastName"
            id="lastName"

            // prints twice
            onBlur={(e) => {
              dispatch({
                type: "INPUT",
                payload: {
                  name: e.target.name,
                  value: e.target.value,
                },
              });
            }}
          />
        </div>
        <div>
          <label htmlFor="email">
            Email
          </label>
          <input
            type="email"
            name="email"
            id="email"

            // prints twice
            onBlur={(e) => {
              dispatch({
                type: "INPUT",
                payload: {
                  name: e.target.name,
                  value: e.target.value,
                },
              });
            }}
          />
        </div>
        <div>
          <h1>Gender</h1>
          <div>
            <div>
              <input
                type="radio"
                id="male"
                name="gender"
                value="male"

                // prints twice
                onClick={(e) => {
                  dispatch({
                    type: "INPUT",
                    payload: {
                      name: e.target.name,
                      value: e.target.value,
                    },
                  });
                }}
              />
              <label htmlFor="male">
                Male
              </label>
            </div>
            <div>
              <input
                type="radio"
                id="female"
                name="gender"
                value="female"

                // prints twice
                onClick={(e) => {
                  dispatch({
                    type: "INPUT",
                    payload: {
                      name: e.target.name,
                      value: e.target.value,
                    },
                  });
                }}
              />
              <label htmlFor="female">
                Female
              </label>
            </div>
            <div>
              <input
                type="radio"
                id="other"
                name="gender"
                value="other"

                // prints twice
                onClick={(e) => {
                  dispatch({
                    type: "INPUT",
                    payload: {
                      name: e.target.name,
                      value: e.target.value,
                    },
                  });
                }}
              />
              <label htmlFor="other">
                Other
              </label>
            </div>
          </div>
        </div>
        <div>
          <label htmlFor="education">
            Education
          </label>
          <select
            name="education"
            id="education"

            // prints twice
            onChange={(e) => {
              dispatch({
                type: "INPUT",
                payload: {
                  name: e.target.name,
                  value: e.target.value,
                },
              });
            }}
          >
            <option value="SSC">SSC</option>
            <option value="HSC">HSC</option>
            <option value="underGrad">Under Graduate</option>
            <option value="graduate">Graduate</option>
          </select>
        </div>
        <div>
          <label>Number of PCs</label>
          <div>
            <button>
              -
            </button>
            <div>
              <span>0</span>
            </div>
            <button>
              +
            </button>
          </div>
        </div>
        <div>
          <label htmlFor="feedback">
            Feedback
          </label>
          <textarea
            name="feedback"
            id="feedback"
            cols="30"
            rows="4"

            // prints twice
            onBlur={(e) => {
              dispatch({
                type: "INPUT",
                payload: {
                  name: e.target.name,
                  value: e.target.value,
                },
              });
            }}
          ></textarea>
        </div>

        <div>
          <div>
            <input
              type="checkbox"
              name="term"
              id="terms"

              // prints twice
              onClick={() => dispatch({ type: "TOGGLE" })}
            />
            <label htmlFor="terms">I agree to terms and conditions</label>
          </div>
          <button
            type="submit"
          >
            Submit
          </button>
        </div>
      </form>
    </div>
  );
};

export default LongForm;

I have looked into other problems But I am failing to understand why is it happening to my code. How can I solve this?


Solution

  • try to define these handlers as local functions inside your component. and check if your app wrapped with React.StrictMode