skip to Main Content

I am using this typescript code to set the UI loading status animation in react hooks:

React.useEffect(() => {
    setUserDocList(projList.projects);
    setProjFolders(projList.folders);
    setProjLoading(false);
}, [projList]);

and listening the projList like this:

const { projList, folderProjList } = useSelector((state: AppState) => state.proj);

When projList changes, will trigger the useEffect. Now I facing the issue that the projList will trigger before the http response change the global state. Is it possible only capture the http response change events? Only set the loading status to false with the http response change. The http request look like this:

export function getProjectList(req: QueryProjReq) {
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(req)) {
    params.append(key, value);
  }
  const config: AxiosRequestConfig = {
    method: 'get',
    url: '/tex/project/list',
    params: params
  };
  const actionTypeString: string = ProjectActionType[ProjectActionType.GET_PROJ_LIST];
  return XHRClient.requestWithActionType(config, actionTypeString, store);
}

the http request will get the projects from server side and dispath the result to reducer. I want to trigger the UI loading to false after recive the http response project list. But now the useEffect will trigger when init the component, so the loading animation will never render in UI because everytime initial the component the loading status will set to false. I only want to set the loading status to false after the projects response.

2

Answers


  1. To ensure that the loading status is set to false only after the HTTP response has successfully updated the projList in your global state, you need to differentiate between the initial state of projList and its state after receiving the HTTP response. This can be achieved by tracking the loading state more explicitly in relation to your HTTP request.

    Here’s a strategy you can employ:

    Define a loading state in your global store: If not already defined, maintain a loading state related to project list requests in your global store. This state should be set to true when the HTTP request starts and set to false when the request completes (both in success and failure cases).

    Trigger loading state changes with your HTTP request: Adjust your action creators to dispatch actions that toggle this loading state at the start and end of your HTTP requests.

    Listen to the loading state in your component: Instead of (or in addition to) listening to changes in projList, also listen to changes in the loading state you’ve defined in the global store. Use this state to control the UI loading indicator.

    Here’s how you can implement these steps:

    Step 1 & 2: Adjusting the Global Store and HTTP Request Handling
    Adjust your action creator to manage the loading state:

    export function getProjectList(req: QueryProjReq) {
      return async (dispatch) => {
        dispatch({ type: 'SET_PROJ_LOADING', payload: true }); // Start loading
        const params = new URLSearchParams();
        for (const [key, value] of Object.entries(req)) {
          params.append(key, value);
        }
        const config: AxiosRequestConfig = {
          method: 'get',
          url: '/tex/project/list',
          params: params
        };
        try {
          const response = await XHRClient.request(config);
          dispatch({ type: ProjectActionType.GET_PROJ_LIST, payload: response.data });
          dispatch({ type: 'SET_PROJ_LOADING', payload: false }); // Stop loading
        } catch (error) {
          console.error("Fetching projects failed:", error);
          dispatch({ type: 'SET_PROJ_LOADING', payload: false }); // Stop loading in case of error
        }
      };
    }
    

    Step 3: Listen to the Loading State in Your Component
    In your component, listen to the loading state:

    import React from 'react';
    import { useSelector } from 'react-redux';
    import { AppState } from './store'; // Adjust the import path according to your project structure
    
    const MyComponent: React.FC = () => {
      const { projList, isLoadingProjList } = useSelector((state: AppState) => ({
        projList: state.proj.projList,
        isLoadingProjList: state.proj.isLoadingProjList,
      }));
    
      React.useEffect(() => {
        if (!isLoadingProjList) {
          // Now we are sure projList is updated due to HTTP response
          // Do something with projList, for example, update local component state
        }
      }, [projList, isLoadingProjList]);
    
      return (
        <div>
          {isLoadingProjList ? <div>Loading...</div> : <div>Your content here</div>}
        </div>
      );
    };
    

    export default MyComponent;
    Make sure your reducer handles actions related to setting the loading state (SET_PROJ_LOADING in the example) by updating isLoadingProjList in the global state.

    By following these steps, you ensure that your component’s UI loading indicator accurately reflects the loading status of your HTTP request, only disappearing once the projList has been successfully updated in response to the HTTP request.

    Login or Signup to reply.
  2. Try this NPM package.

    https://www.npmjs.com/package/@codewagon/active-stream

    It works well for us. We Subscribe to the events on the component

    import ActiveStream from '@codewagon/active-stream';
    const activeStream = new ActiveStream();
    //subscribe to the stream
    activeStream.stream.subscribe((event) => {
        console.log(event);
    })
    

    and fire the event from the Services once there is a response.

    //push data into the stream from the HTTP service
    activeStream.request({name: 'http-response', data: {name: 'Victor'}});
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search