简体   繁体   中英

React dispatch going in the infinite loop

While making a post request my request is going in a loop. Not sure why it's happening. Its happening at the handleSubmit of the form. I referred few question from stackoverflow but it did not helped me. Still looking for a solution. Dammm its Ruined my SUNDAY.

import React, { useState } from "react";
import { Link } from "react-router-dom";
import { FORGOT_PASSWORD } from "../../redux/types";
import { useDispatch, useSelector } from "react-redux";
import AuthLayout from "../../layouts/Auth";

export default function ForgotPassword() {
  const dispatch = useDispatch();

  const [email, setEmail] = useState("");

  const handleSubmit = async (e) => {
    console.log(email,'---get email')
    e.preventDefault();
    const payload = { email };
    //loginUser(payload)
    console.log(payload,'=====')
    dispatch({ type: FORGOT_PASSWORD, payload });
  };

  return (
    <AuthLayout>
      <div className="container mx-auto px-4 h-full">
        <div className="flex content-center items-center justify-center h-full">
          <div className="w-full lg:w-4/12 px-4">
            <div className="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded-lg bg-blueGray-200 border-0">
              <div className="rounded-t mb-0 px-6 py-6">
                <div className="text-blueGray-400 text-center mb-3 font-bold">
                  <center>Reset your password </center>
                </div>
                <hr className="mt-6 border-b-1 border-blueGray-300" />
              </div>
              <div className="flex-auto px-4 lg:px-10 py-10 pt-0">
                <form onSubmit={handleSubmit}>
                  <div className="relative w-full mb-3">
                    <label
                      className="block uppercase text-blueGray-600 text-xs font-bold mb-2"
                      htmlFor="grid-password"
                    >
                      Email
                    </label>
                    <input
                      value={email}
                      onChange={(e) => setEmail(e.target.value)}
                      type="email"
                      required
                      className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
                      placeholder="Email"
                    />
                  </div>
                  <div className="text-center mt-6">
                    <button
                      className="bg-blueGray-800 text-white active:bg-blueGray-600 text-sm font-bold uppercase px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 w-full ease-linear transition-all duration-150"
                      type="submit"
                    >
                      {/* {loading ? "Sending email..." : "Reset Password"} */} Reset Password
                    </button>
                  </div>
                </form>
              </div>
            </div>
            <div className="flex flex-wrap mt-6 relative">
              <div className="w-1/2">
                <Link to="/auth/forgot-password" className="text-blueGray-200">
                  Login?
                </Link>
              </div>
              <div className="w-1/2 text-right">
                <Link to="/auth/register" className="text-blueGray-200">
                  Create new account
                </Link>
              </div>
            </div>
          </div>
        </div>
      </div>
    </AuthLayout>
  );
}

This is my Redux looks like

import { LOGIN, REGISTER, LOGOUT, FORGOT_PASSWORD } from "../types";

const initialState = {};

const auth = (state = initialState, { type, payload }) => {
  switch (type) {
    case LOGIN:
      return { ...state, ...payload };
    case REGISTER:
      return { ...state, ...payload };
    case LOGOUT:
      return { ...state, ...payload };
    case FORGOT_PASSWORD:
      return { ...state, ...payload };
    default:
      return state;
  }
};

export default auth;

And this is how my SAGA looks like

export function* forgotPassword({ payload }) {
  yield put({ type: FORGOT_PASSWORD, payload: { loading: true } });
  try {
    const { status } = yield authService.forgotPassword(payload);
    if (status === 204) {
      const key = 'updatable';
      // notification.success({ message: "Logged in successfully" });
      message.loading({ content: 'Loading...', key });
      message.success({ content: 'Reset password link sent to your email!', key, duration: 4 });
      //window.location.replace("/dashboard");
    } else yield put({ type: FORGOT_PASSWORD, payload: { loading: false } });
  } catch (error) {
    yield put({ type: FORGOT_PASSWORD, payload: { loading: false } });
  }
}

The issue I when I submit that form it just goes in loop. INFINITE LOOP

EDIT-

After debugging I see it keep looping at SAGA and SERVICE CALL [JUST IN CASE THE API I AM CALLING HAS RESPONSE SUCCESS CODE 204]

// THIS IS SERVICE CALL
const userInstance = axios.create({
  baseURL: 'http://localhost:3005/v1/',
  headers: { "Content-Type": "application/json" },
  timeout: 10000,
  responseType: "json",
  validateStatus: (status) => status < 400,
});


// BELOW IS THE API call I am making
    async function forgotPassword(payload) {
      return userInstance
        .post("/auth/forgot-password", payload)
        .then((response) => {
          if (response) {
            return response;
          }
          return false;
        })
        .catch((err) => console.log(err));
    }

And this is my SAGA FUCNTION

  export function* forgotPassword({ payload }) {
      console.log('======AT SAGA', payload);
      yield put({ type: FORGOT_PASSWORD, payload: payload });
      try {
               // here below line the SERVICE function for API call is called
        const { status } = yield forgotPassword(payload);
        if (status === 204) {
          const key = 'updatable';
          // notification.success({ message: "Logged in successfully" });
          message.loading({ content: 'Loading...', key });
          message.success({ content: 'Reset password link sent to your email!', key, duration: 4 });
          //window.location.replace("/dashboard");
        } else yield put({ type: FORGOT_PASSWORD, payload: { loading: false } });
      } catch (error) {
        yield put({ type: FORGOT_PASSWORD, payload: { loading: false } });
      }
    }
//EXPORT ALL TO ROOT
export default function* rootSaga() {
  yield all([
    takeEvery(LOGIN, login),
    takeEvery(REGISTER, register),
    takeEvery(LOGOUT, logoutUser),
  ]);

  yield all([takeEvery(FORGOT_PASSWORD, forgotPassword)]);
}

SO AFTER DEBUGGING IT JUST KEEP LOOPING INFINITE - FROM SAGA FUNCTION TO THE SERVICE CALL FUNCTION WHERE ITs been called at SAGA.

I'm pretty sure it's because you use the action type "FORGOT_PASSWORD" for triggering both state update in reducer and the saga function.

You said you've tried my solution. But I doubt you're still missing some points. So I'mma post the solution again in full details.

My reasoning:

  1. put in saga function is effectively dispatch in redux's term.
  2. You dispatch({ type: "FORGOT_PASSWORD" }) from handleSubmit to trigger initial run of saga, the action first arrives at the redux store
  3. The saga middleware pickup the action because takeEvery("FORGOT_PASSWORD", forgotPassword) , it's now routed to forgotPassword saga function
  4. forgotPassword run some side-effects, and eventually you wanna tell the redux reducer to update the state. So you put({ type: "FORGOT_PASSWORD" }) wishing it would reach the reducer.
  5. Surprisingly, this action is once again pickup by the saga middleware in step 3, routed back to forgotPassword , now you're in a infinite loop.

Notice throughout the above explanation I always use string literals to present action types? "FORGOT_PASSWORD" with double quotes.

You said in the comment

those are just CONSTANTS so I think does not matter

Obviously you missed the crucial point. Off course I don't mean to change the constants variable name, I mean change the action types' string literal .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM