Search code examples
reactjsreduxredux-saga

infinite loop with react/redux


I have tiredlessly tried everything i can find on stack for this issue and am getting no where. We are using react/typescript. redux, and saga. I have a list of categories to bring back for nav list and using useEffect to dispatch the action to redux store. our tsx.file:

  const dispatch = useDispatch();
  const categories = useSelector((state) => state?.categories?.payload);
  const loadCategories = () => {
    dispatch(getCategories(categories));
  };

  useEffect(() => {
   loadCategories();
  }, []);
 
    {categories?.map((x, index) => (
      <Link href={"/store/" + `${x.name}` + "/s"}>
        <a
          type="button"
          id={`${x.name}`}
          title={`${x.name}`}
          className={"xl:px-3 px-2 py-[1.15rem] font-normal"}>
          {x.name}
        </a>
      </Link>
    ))}

Network traffic just shows hundreds of requests going out to the category endpoint -- stumped!

still stuck so adding our redux/saga files actions:

import {GET_CATEGORIES} from './actionTypes'

export const getCategories = (categories: any) => {
    return {
        type: GET_CATEGORIES,
        payload: categories,
    }
}

reducer:

import {GET_CATEGORIES} from './actionTypes'

const reducer = (state = [], action) => {
    switch (action.type) {
        case GET_CATEGORIES:
            state = {
                ...state,
                payload: action.payload,
            }
            break
        default:
            state = {...state}
            break
    }
    return state
}
export default reducer

saga:

let categoriesApiService = container.resolve(CategoriesApiService)

const categoryApi = async () => {
    return firstValueFrom(
        categoriesApiService.GetCategoryTree({
            path: {version: '1'},
            query: {},
        })
    )
}

function* getCategoriesTree() {
    try {
        let categoryTreeDTO: CategoryTreeDTO = yield call(categoryApi)
        yield put(getCategories(categoryTreeDTO))
    } catch (error: any) {
        yield put(apiError(error?.response?.data?.message))
    }
}

export function* watchGetCategories() {
    yield takeEvery(GET_CATEGORIES, getCategoriesTree)
}

function* categorySaga() {
    yield all([fork(watchGetCategories)])
}

export default categorySaga

Solution

  • The problem is that you are using the same action to start the saga & to store the fetched data:

    component: dispatch(getCategories(categories))
    saga: yield put(getCategories(categoryTreeDTO))

    so every time data are fetched the saga is triggered again.

    What you want to do is to have different action for storing the fetched data, e.g.:

    yield put(getCategoriesSuccess(categoryTreeDTO))
    

    (also update your action type in reducer)