简体   繁体   English

使用反应时的 Promise 数据和 axios

[英]Promise data when using react and axios

in this code whenever I try to direct to /dashboard it wouldn't wait for the response of axios and goes immediately to return part and it use loggedin with it's default value which is undefined here.在此代码中,每当我尝试定向到/dashboard时,它都不会等待 axios 的响应,而是立即返回部分,并使用此处undefined的默认值loggedin Well I guess I should use promises but I don't know how... So I would appreciate it if someone could help.好吧,我想我应该使用承诺,但我不知道如何...所以如果有人能提供帮助,我将不胜感激。

import axios from 'axios';
import React, { useEffect, useRef, useState } from 'react';
import { Redirect } from 'react-router';
import OverallCondition from "./dashOverall";
import Toolbar from "./dashToolbar";

export default function Dashboard(){
    const [loggedin, check] = useState()
    axios.get('/loggedin')
        .then(response => {
            check(response.data)
        })
        .catch(err => console.error(err));
    return <section className='dashboard'>
            {loggedin ? <div>
                <Toolbar/>
                <OverallCondition/>
            </div> : <Redirect to='/login'/>}
    </section>
}```

You need to use useEffect hook to make the HTTP request.您需要使用useEffect钩子来发出 HTTP 请求。

Making the HTTP request at the top-level inside your function component will trigger a new HTTP request every time your component is re-rendered.在 function 组件的顶层发出 HTTP 请求将在每次重新呈现组件时触发新的 HTTP 请求。

Also, since the axios.get(...) is asynchronous, code below the axios.get(...) will execute before the request is completed.此外,由于axios.get(...)是异步的,因此axios.get(...)下面的代码将在请求完成之前执行。

To handle this situation appropriately, follow the steps mentioned below:要适当地处理这种情况,请按照以下步骤操作:

  1. Create a state that represents whether the HTTP request is pending or not.创建一个 state 表示 HTTP 请求是否处于挂起状态。 Its initial value should be true它的初始值应该是真实的

    const [isPending, setIsPending] = useState(true);
  2. Use the useEffect hook to make the HTTP request.使用useEffect挂钩发出 HTTP 请求。 Making HTTP requests at the top-level inside the function component is NOT the right approach - you don't want to make a request every time your component re-renders在 function 组件内的顶层发出 HTTP 请求不是正确的方法——您不想在每次组件重新呈现时都发出请求

    Also don't forget to set isPending to false , otherwise user will continue to see the loading spinner even after the request has completed.另外不要忘记将isPending设置为false ,否则即使在请求完成后用户仍会继续看到加载微调器。 You can use the finally() method to call setIsPending(false)您可以使用finally()方法调用setIsPending(false)

     useEffect(() => { axios.get('/loggedin').then(response => setLoggedIn(response.data)).catch(err => console.error(err)).finally(() => setIsPending(false)); }, []);

    Empty array passes as a second argument to the useEffect hook will ensure that the HTTP request is initiated only once, after the initial render of the component空数组作为第二个参数传递给useEffect挂钩将确保 HTTP 请求仅在组件初始渲染后启动一次

  3. While the request is pending, show some loading spinner to the user.在请求挂起时,向用户显示一些加载微调器。 When the component first renders, as the isPending is true, user will see the loading spinner当组件首次呈现时,由于isPending为真,用户将看到加载微调器

    if (isPending) { return <Spinner/>; // you need to create the "Spinner" component }

Here's how you could implement the above steps in your code:以下是如何在代码中实现上述步骤:

function Dashboard() {
    const [loggedin, setLoggedIn] = useState();

    // this state will be used to show a loading spinner
    const [isPending, setIsPending] = useState(true);

    // for HTTP request, use the "useEffect" hook
    useEffect(() => {
       axios.get('/loggedin')
        .then(response => setLoggedIn(response.data))
        .catch(err => console.error(err))
        .finally(() => setIsPending(false));
    }, []);

    // show a spinner to the user while HTTP 
    // request is pending
    if (isPending) {
       return <Spinner/>;  
    }
    
    return (
       <section className='dashboard'>
          {loggedin ? (
                <div>
                  <Toolbar/>
                  <OverallCondition/>
                </div> 
              ) : <Redirect to='/login'/>
           }
       </section>
     );
}

Issues with the code代码问题

Use a better terminology with the useState return在 useState 返回中使用更好的术语

Instead of代替

const [loggedin, check] = useState()

Use使用

const [loggedin, setLoggedin] = useState()

Understand the life cycle了解生命周期

Your axios.get is inside the function body, all code there will be executed on every render, it is certainly not what you wanted, for operations that may have side effects, you need to use the useEffect hook https://reactjs.org/docs/hooks-effect.html你的 axios.get 在 function body 里面,所有的代码都会在每次渲染时执行,这肯定不是你想要的,对于可能有副作用的操作,你需要使用 useEffect hook https://reactjs.org /docs/hooks-effect.html

The useEffect hook allows you to control better when the code will execute, in your case, you want it to run once useEffect 挂钩允许您更好地控制代码何时执行,在您的情况下,您希望它运行一次

const ShowOnceLoaded = ({ isLoaded, children }) => {
   if (!isLoaded)
     return <p>Loading...</p>

   return <>{children}</>
}

export default function Dashboard(){
    const [ isLoaded, setIsLoaded ] = useState(false)
    const [loggedin, setLoggedin] = useState(false)

    React.useEffect(() => {
      axios.get('/loggedin')
        .then(response => {
            setLoggedin(true)
            setIsLoaded(true)
        })
        .catch(err => console.error(err));
    }, [])
    
    return <section className='dashboard'>
            <ShowOnceLoaded isLoaded={isLoaded}>
            {loggedin ? <div>
                <Toolbar/>
                <OverallCondition/>
            </div> : <Redirect to='/login'/>}
            </ShowOnceLoaded>
    </section>
}

In addition to what you had, now there is a state set once the request is complete, only then we can decide if the user is logged in or not, otherwise, we will redirect the user even before the request is done, as the state initializes as false by default除了你拥有的,现在有一个 state 设置,一旦请求完成,只有这样我们才能决定用户是否登录,否则,我们会在请求完成之前重定向用户,如 state默认情况下初始化为 false

The empty array on useEffect is used to run the code only when the component mounts useEffect 上的空数组仅用于在组件挂载时运行代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM