最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React render page after API call - Stack Overflow

programmeradmin3浏览0评论

When I navigate between pages in my React app, a see a bounce at each page (meaning that page is rendered first without any data [e.g. username, date of birth, images], then few milliseconds/seconds later some details appear on the screen as the API request has finished and updated the state.

For example I have the following pages:

<div className="home" onClick={() => history.push('/')}></div>
<div className="user" onClick={() => history.push('/user')}></div>
<div className="settings" onClick={() => history.push('/settings')}></div>

This results in behavior that when I click 'settings' button I first go to /settings route and then ponents starts rerendering and bouncing while making API requests. In each of these pages I make one or multiple API requests to get data. I make these requests using useEffect hook. For example:

const Settings = () => {
  const [userDetails, setUserDetails] = useState(null);
  const [userImages, setUserImages] = useState([]);

  useEffect(() => {
    const getUserDetails = async () => {
     const response = await getUserSettingsDetails();
     setUserDetails(response.data);
   }
   const getUserImages = async = () => {
     const response = await getUserSettingsImages();
     setUserImages(response.data);
  }
  getUserDetails();
  getUserImages();
  }, []);

  return ( 
     ... 
  );
}

What I want to achieve:

I want that when I am for example on 'homepage', and click to go to 'settings', to navigate and render Settings page only after the API requests finished and I can have all details on the screen immediately. I have a nice line loading ponent that I want to display in header while loading. (Similar to what YouTube has, it displays a red progress bar when navigating). I also use Redux for this project and I think it could be used here but I do not understand how to do this. Could anyone please explain how to achieve such behavior.

When I navigate between pages in my React app, a see a bounce at each page (meaning that page is rendered first without any data [e.g. username, date of birth, images], then few milliseconds/seconds later some details appear on the screen as the API request has finished and updated the state.

For example I have the following pages:

<div className="home" onClick={() => history.push('/')}></div>
<div className="user" onClick={() => history.push('/user')}></div>
<div className="settings" onClick={() => history.push('/settings')}></div>

This results in behavior that when I click 'settings' button I first go to /settings route and then ponents starts rerendering and bouncing while making API requests. In each of these pages I make one or multiple API requests to get data. I make these requests using useEffect hook. For example:

const Settings = () => {
  const [userDetails, setUserDetails] = useState(null);
  const [userImages, setUserImages] = useState([]);

  useEffect(() => {
    const getUserDetails = async () => {
     const response = await getUserSettingsDetails();
     setUserDetails(response.data);
   }
   const getUserImages = async = () => {
     const response = await getUserSettingsImages();
     setUserImages(response.data);
  }
  getUserDetails();
  getUserImages();
  }, []);

  return ( 
     ... 
  );
}

What I want to achieve:

I want that when I am for example on 'homepage', and click to go to 'settings', to navigate and render Settings page only after the API requests finished and I can have all details on the screen immediately. I have a nice line loading ponent that I want to display in header while loading. (Similar to what YouTube has, it displays a red progress bar when navigating). I also use Redux for this project and I think it could be used here but I do not understand how to do this. Could anyone please explain how to achieve such behavior.

Share Improve this question edited Apr 26, 2021 at 22:27 user12051965 asked Apr 26, 2021 at 22:18 user12051965user12051965 15712 silver badges39 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 2

You can create an extra state called isLoading and set it true when any fetch of data starts. Then, below the await statement, you can set isLoading to false.

So, with this, you can use the isLoading state in your JSX code, to make a conditional rendering, for example, you can display a Loading Component while the isLoading variable has the value of true, then, when the variable is false, display your page as you want.

const Settings = () => {
  const [state, setState] = useState({});
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const getAllInformation = async () => {
      // start loading
      setIsLoading(true);
      // make the request here
      const data = await fetch();
      setState({ ...data });
      // already finished here
      setIsLoading(false);
    };
    getAllInformation()
  }, []);

  return (
    <div>
      {isLoading ? (
        <Loading />
      ) : (
        {
          /* MORE CODE */
        }
      )}
    </div>
  );
};

hi I think you can use Promise.all([]) and a loading state

const Settings = () => {
 const [userDetails, setUserDetails] = useState(null);
 const [userImages, setUserImages] = useState([]);
 const [loading,setLoading] = useState(false)

 const getUsersInfos = async () => {
  try {
   const result = await new Promise.all([
     getUserSettingsDetails(),
     getUserSettingsImages(),
   ])

   const details = result[0]
   const images = result[1]

   //i'm not sure if we need to test
   if(details.data && images.data){
     setUserDetails(details.data);
     setUserImages(images.data);
     setLoading(true)
   }

  } catch (error) {
   console.log(error);
 }
}

useEffect(() => {
  getUsersInfos();
}, []);

return ( 
  <>
   {loading && (
     ...
   )}
  </>
 );
}

Although I believe @Daphaz answer is pretty well, I'll go with a better and cleaner approach using redux-thunk or redux-sagas. With redux you can only do simple synchronous updates, and here you will be doing asynchronous updates hence you will need a middleware like those I mentioned.

Redux-thunk Redux-sagas

There are tons of examples of usings this middlewares to achieve exactly what you are looking for.

发布评论

评论列表(0)

  1. 暂无评论