How to compare values from react redux state in hooks

I have recently written a table component using hooks , and every time page loads there is an API call to backend, so meanwhile there is a loading Spinner will be shown until there is an response from the API. I’m using redux as state management, so when there is a response from API , an action is dispatched and state is updated. So the problem here is ,usually in class component we can compare prevProps and nextProps using

componentDidUpdate(prevProps){
  if(this.props.someState !== prevProps.someState){
      // do something
    }
}

but i’m not sure how to achieve the same using Hooks. I also referred this stackoverflow question How to compare oldValues and newValues on React Hooks useEffect?

but this solution doesn’t seem to be working in my case . I did try creating custom hook usePrevious and creating a ref to compare current value ,this didn’t solve my issue.

Here’s my part of code.

let loading = true;

let tableData = useSelector((state) => {
   
    if (
      state.common.tableDetails.data &&
      state.common.tableDetails.status === true
    ) {
      loading = false;
      return state.common.tableDetails.data;
    }
   
    if (
      state.common.tableDetails.data &&
      state.common.tableDetails.status === false
      
    ) {
      loading = true;
    }
    return [];
  });

// table component

<Fragment>
  { 
   loading === true ? <Spinner />  :  <TableComponent tableData={tableData }/>
   }
</Fragment>

So whenever the component loads, if there is any data present in redux state , that data is shown and no comparison is done for prevProps and nextProps because of which Loading spinner won’t show up and after a response of newly called api state will be update and new data will be shown in Table.

UPDATE 1: Here’s the code for dispatch and action and reducer

 useEffect(() => {
    
    dispatch(fetchDetails(params.someID));

  }, [dispatch, params.someID]);

Action File

export const fetchDetails = (data) => (dispatch) => {
  axios
    .post(
      `${SomeURL}/fetchAll`,
      data
    )
    .then((res) => {
      if (res.data.status) {
        dispatch({
          type: FETCH_DETAILS,
          payload: res.data,
        });
      }
    })
    .catch((err) => console.log(err));
};

Reducer File

const initialState = {
  tableDetails: {},
};

export default function (state = initialState, action) {
  switch (action.type) {
    case FETCH_DETAILS:
      return {
        ...state,
        tableDetails: action.payload,
      };

    default:
      return state;
  }
}


Answer

You can implement simple validation to achieve what you want. I will assume your tableData has an id, then you can validate like this:

useEffect(() => {
    // don't fetch the same table
    if(tableData?.id !== params.someID {
      dispatch(fetchDetails(params.someID));
    }
}, [dispatch, params.someID, tableData?.id]);

UPDATE 1

To compare previous table data to new feched one you could do that in the action creator:

  1. move loading state to redux store.
  2. use getState function which is the second argument recived by action creator (assuming that you are using redux-thunk)
  3. before dispatching the action, compare new tableData with data in the store(prev tableData).
  4. do your check and update loading state.

export const fetchDetails = (data) => (dispatch, getState) => {
  axios
    .post(
      `${SomeURL}/fetchAll`,
      data
    )
    .then((res) => {
      if (res.data.status) {
        const prevTableData = getState().tableData;
        
        // compare prev and new table data
        if(isDiff(prevTableData, res.data) {
            // Do something...
        }
        dispatch({
          type: FETCH_DETAILS,
          payload: res.data,
        });
      }
    })
    .catch((err) => console.log(err));
};