【问题标题】:axios not getting data on first renderaxios 在第一次渲染时没有获取数据
【发布时间】:2022-01-19 16:51:28
【问题描述】:

所以我尝试在第一次渲染时获取数据,然后对其进行一些计算并将其显示在表格中。但是在第一次渲染之后 fetchArray 的状态是一个空数组,如果我点击更新表按钮,它只会获取第一部分,即用户订单:After first render

第一次渲染后,当我单击更新表按钮时,它再次渲染,我只从 DB fetch 中获取数据: After update table click

现在,在第三次点击之后,一切终于呈现出来了:After 2nd click

这些是正在使用的文件:

OrderList.js

export default function OrderList() {
  
  const [userInfo, setUserInfo] = useState([]);
  const [loading, setLoading] = useState(true);
  const [errorMsg, setErrorMsg] = useState("");
  const [fetchArray, setFetchArray] = useState([]);
  const [state, dispatch] = useContext(Context)
  const [authenticatedUser, setAuthenticatedUser] = useState(true)

  const orders = []

    //get the logged in user from local storage then get user ID
    const getAuthUser = () =>{
      try{
          const userId = localStorage.getItem('user')
          const foo = JSON.parse(userId)
          const id = foo.auth.user
          //console.log(id)
          if(!id || id == null){
            console.log(userId)
            setAuthenticatedUser(false)
          }else{
              return id
          }

      }catch(e){
          console.log(e)
          console.log("No auth")
      }
  }

  const deleteOrder = async(row) =>{

    const order = {
      ticker: row.ticker,
      amount: row.amount,
      price: row.price,
      date: row.date,
      comments: row.comments
    }

    console.log("Deleted " + JSON.stringify(order))

    /*try{
      await axios.delete(`http://localhost:8081/api/auth/delete-order/${getAuthUser()}`, order)
      .then((res) =>{
        console.log("deleted " + JSON.stringify(res))
        setIsDelete(true)
      }).catch(e =>{
        console.log(e)
      })
    }catch(e){
      console.log("inside deleteORder: " + e)
    }*/

  }

  //Calculates the profit or loss for a single position
  const profitLossCalculator = (price, currentPrice, quantity) => {
    let profitLoss = 0;

    if (currentPrice) {
      profitLoss = (currentPrice - price) * quantity;
    }
    return profitLoss.toFixed(2)
  }

  //Calculates the profit or loss for the whole portfolio
  const profitLossTotalCalculator = (fetchArray) => {
    let profitLossTotal = 0;

    fetchArray.forEach((stock) => {
        if (!isNaN(Number(stock.profitLoss))) {
            profitLossTotal += Number(stock.profitLoss);
        }
    });

    return profitLossTotal.toFixed(2);
  }

  const getOrders = ()=>{

    setErrorMsg("")
    setFetchArray([])
  
        axios.get(`http://localhost:8081/api/auth/user/${getAuthUser()}`)
        .then(response => {
            if(response){
                setUserInfo(response.data)
                console.log(userInfo)

            }else if(!response.data[orders] < 1){
              setErrorMsg("No orders to display. Add orders and try again")
            }
        }).then((() =>{
          if(fetchArray.length > 0){
            console.log("jeje")
          }
        }))
        .catch(e =>{
            setErrorMsg("Something went wrong while trying to get your orders")
            console.log(errorMsg + e)
        })
        setLoading(false)

      const foo = userInfo.orders
      for(var i in foo){
        const fee = foo[i]
        setFetchArray(prev =>[...prev, fee])
      }

      if(fetchArray.length > 0){
        stockFetcher(fetchArray, setFetchArray, profitLossCalculator)
      }
  }

    

  useEffect(() =>{
    getOrders()
  }, [])







  //if data is being fetched
  if(loading) {
    return (
      <>
      <p>Data is loading...</p>
      </>)
}
  
  return (
    <div>
      {authenticatedUser ? (
        <div style={{display: "flex", width: "150vh", minHeight: "100vh"}}>
        <div style={{display: "inline-block", width: "150vh"}}>
          <TableContainer component={Paper} sx={{maxWidth: 1200, padding: 6, margin: "auto", marginTop: 10, marginBottom: 10}}>
            <h1 style={{textAlign: "center"}}>Your orders, {userInfo.firstName}</h1>
            <div> 
              <h4>
                Total profit: <p style={{color: `${profitLossTotalCalculator(fetchArray) <= 0 ? "red" : "green"}`}}>{profitLossTotalCalculator(fetchArray)}€</p>
              </h4>
            </div>
            <Table sx={{padding: 20, minHeight: 350,}} aria-label="simple table">
              <TableHead>
                <TableRow sx={{maxHeight: 600}}>
                  <TableCell></TableCell>
                  <TableCell>Ticker</TableCell>
                  <TableCell align="right">Price(€)</TableCell>
                  <TableCell align="right">Amount</TableCell>
                  <TableCell align="right">Date</TableCell>
                  <TableCell align="right">Current price</TableCell>
                  <TableCell align="right">Profit/Loss</TableCell>
                  <TableCell align="right">Comments</TableCell>
                </TableRow>
              </TableHead>
              <TableBody>
                {fetchArray ? (fetchArray.map((row) => (
                    <TableRow
                    key={row.ticker}
                    sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                  >
                  <TableCell>
                    <Button onClick={() => deleteOrder(row)}>
                      <DeleteIcon />
                    </Button>
                    </TableCell>
                    <TableCell component="th" scope="row">
                      {row.ticker}
                    </TableCell>
                    <TableCell align="right">{row.price}€</TableCell>
                    <TableCell align="right">{row.amount}</TableCell>
                    <TableCell align="right">{row.date}</TableCell>
                    <TableCell align="right">{row.currentPrice}€</TableCell>
                    <TableCell align="right" style={{color: `${row.profitLoss <= 0 ? "red" : "green"}`}}>
                    {row.profitLoss}€
                    </TableCell>
                    <TableCell align="right">{row.comments}</TableCell>
                  </TableRow>
                ))) : (
                  <span style={{color: "red"}}>Couldn't retrieve data</span>
                )}
              </TableBody>
            </Table>
          </TableContainer>
          <button onClick={() => getOrders()}>Update table</button>
        </div>
      </div>
      ) : (
        <block>
        <h1>You are not logged in!</h1>
        <a href="/login">Go back</a>
        </block>
    )}
      
  </div>
  )
}

StockFetcher.js

这里发生了所有外部 api 获取和计算

//Function which fetches the current prices and updates our state with current prices and profit/loss
const stockFetcher = (stocks, setStocks, profitLossCalculator) => {
    stocks.forEach(async(stock) => {
        console.log(stock)
        try {
            const ticker = stock.ticker
            const response = await axios.get(`${STOCK_API_GLOBAL}&symbol=${ticker}&apikey=${TOKEN}`)
            const returnedData = await response.data;
            console.log(returnedData)

            const yesterday = new Date()
            yesterday.setDate(yesterday.getDate())
            const time = yesterday.toISOString().slice(0, 17).replace("T", " ").concat("00")


            const currentPrice = returnedData['Global Quote']['05. price']

            const profitLoss = profitLossCalculator(
                stock.price,
                currentPrice,
                stock.amount
            );

            const stockWithPrice = {
                ...stock,
                currentPrice: currentPrice,
                profitLoss,
            };

            const indexOfStock = stocks.indexOf(stock);
            setStocks((stocks) => [
                ...stocks.slice(0, indexOfStock),
                stockWithPrice,
                ...stocks.slice(indexOfStock + 1),
            ]);
        } catch (error) {
            /*The option how to handle the error is totally up to you. 
                Ideally, you can send notification to the user */
            console.log("error with stockFetcher: " + error);
        }
    });

    return setStocks
};

export default stockFetcher;

我想我的问题是为什么 useState 不在 fetch 中设置自己。如果它在第一次渲染时设置,那么一切都会好起来的。

【问题讨论】:

  • 获取远程数据是异步的,不会阻塞渲染,所以如果你调用setState然后做一些异步的东西(比如用axios获取数据),这将再次调用setState,react 将呈现在对setState 的调用之间。如果您只希望您的应用在所有提取完成后重新呈现,您需要先等待所有结果,然后才调用 setState 获取所有汇总结果。

标签: javascript reactjs api fetch use-effect


【解决方案1】:

您需要使用带有要更新状态的 UseEffect

【讨论】:

  • 你能提供一个代码吗?
  • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
  • 就是这样。如果我将被反弹的状态放在代码中(fetchArray),那么它会进入无限循环的渲染,因为 fetchArray 是在 getOrders 函数中设置的。因此,每次 getOrders 被渲染时,它都会设置 fetchArray 并且如果 fetchArray 状态是 useEffect 的依赖项,则不会停止重新渲染,因为它一直在变化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 2022-10-08
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
相关资源
最近更新 更多