简体   繁体   中英

React Hook useCallback has missing dependencies: 'dir', 'order', 'page', 'perPage', and 'search'

My code: looks like

  //GLOBAL STATE INITIALIZATION
  const page = useSelector((state) => state.users.meta.page);
  const perPage = useSelector((state) => state.users.meta.perPage);
  const order = useSelector((state) => state.users.meta.order);
  const dir = useSelector((state) => state.users.meta.dir);
  const search = useSelector((state) => state.users.meta.search);

  // FUNCTIONS
  const fetchData = useCallback(
    (
      pageNumber = page,
      pageSize = perPage,
      columnOrder = order,
      colDir = dir,
      query = search
    ) => {
      dispatch(
        listUser(pageNumber, pageSize, columnOrder, colDir, searchColArr, query)
      );
    },
    [searchColArr, dispatch]
  );
  //throwing warning above for missing dependencies


  useEffect(() => {
    dispatch(resetState(function () {}));
    fetchData();
  }, [dispatch, fetchData]);

Here, if I add the missing dependencies and replace [searchColArr, dispatch] with [page, perPage, order, dir, searchColArr, search, dispatch] then the program runs on infinite loop on. Becasuse, on listUser action it dispatch

dispatch(
  userActions.USER_LIST_SUCCESS({
    list: data.data,
    meta: data.meta,
  })
);

and this USER_LIST_SUCCESS will update redux state as:

USER_LIST_SUCCESS: (state, action) => {
  state.list = action.payload.list;
  state.meta = action.payload.meta;
  state.isLoading = false;
},

and once this meta state got updated, the page, perPage, order, dir, search will be updated as well and if I add these as dependencies, it fetchData again and while fetching data it update meta state and in this way infinite loops form.

What will be the best solution for this kind of situation? Or eslint-disable-line react-hooks/exhaustive-deps is the only option?

Update: listUser

import user from "../../services/userService";
export const listUser =
  (page, perPage, order, dir, searchCol, search) => async (dispatch) => {
  try {
    dispatch(
      userActions.SET_IS_LOADING({
        isLoading: true,
      })
    );
    const { data } = await user.listUser(
      page,
      perPage,
      order,
      dir,
      searchCol,
      search
    );
    dispatch(
      userActions.USER_LIST_SUCCESS({
        list: data.data,
        meta: data.meta,
      })
    );
  } catch (error) {
    toastify.error(error.response.data.message);
    dispatch(
      userActions.USER_LIST_FAIL({
        errors:
          error.response && error.response.data.errors
            ? error.response.data.errors
            : error.response.data,
      })
    );
  }
};

user.listUser

export async function listUser(
  page,
  perPage,
  order,
  dir,
  searchColArr,
  search
) {
  let searchCol = JSON.stringify(searchColArr);
  return httpClient.get(apiEndpoint, {
    params: {
      page,
      perPage,
      order,
      dir,
      searchCol,
      search,
    },
  });
}

Update2

const handlePageChange = (pageNumber) => {
  fetchData(pageNumber);
};

const handlePageLengthChange = (pageSize) => {
  fetchData(null, pageSize);
};

const handleSort = (newOrder, newDir) => {
  fetchData(null, null, newOrder, newDir);
};

I have a solution. That you will not pass page, perPage, order, dir, search into listUser . Just pass searchCol. Another param will get inside listUser . You can update like this:

  const fetchData = useCallback(() => {
    dispatch(listUser(searchColArr));
  }, [searchColArr, dispatch])

export const listUser =
  ( searchCol ) => async (dispatch, getState) => {
  try {
    dispatch(
      userActions.SET_IS_LOADING({
        isLoading: true,
      })
    );
    const page = getState((state) => state.users.meta.page);
    const perPage = getState((state) => state.users.meta.perPage);
    const order = getState((state) => state.users.meta.order);
    const dir = getState((state) => state.users.meta.dir);
    const search = getState((state) => state.users.meta.search);
    const { data } = await user.listUser(
      page,
      perPage,
      order,
      dir,
      searchCol,
      search
    );
    dispatch(
      userActions.USER_LIST_SUCCESS({
        list: data.data,
        meta: data.meta,
      })
    );
  } catch (error) {
    toastify.error(error.response.data.message);
    dispatch(
      userActions.USER_LIST_FAIL({
        errors:
          error.response && error.response.data.errors
            ? error.response.data.errors
            : error.response.data,
      })
    );
  }
};

Update : If you still want to pass others params, you can check to get data.

listUser = (page, perPage, order, dir, searchCol, search) => async (dispatch, getState) => {
  const page = page || getState((state) => state.users.meta.page);
  ...
};

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