useState不会使用带有React Hooks的async / await来呈现axios调用的结果

时间:2019-10-03 22:05:33

标签: javascript reactjs react-hooks

我是React Hooks的新手,我无法解决State问题。我已经在Stack Overflow的其他地方阅读了有关useState / useEffect的异步性质的信息,看来无论我尝试什么,包括异步/等待,我都无法将JSON数组结果分配给我的[data,callback]以呈现返回数据的元素在我的主App(.js)中的一个简单表中-参见下文。我有一个App.js,一个Hooks.js和一个Tradetable.js,其中填充了元素表(后两个文件都导入了App.js内)。

App.js

import React, { useState, Fragment } from 'react'
import AddTradeForm from './forms/AddTradeForm'
import EditTradeForm from './forms/EditTradeForm'
import TradeTable from './tables/TradeTable'
import { useFetch } from './Hooks'

const App = () => {
    // get Data from API call
    const URL = "http://192.168.1.1:3000/api/queryMyCommodity"; //
    const tradeData = useFetch(URL, {username:'john', channel:'channel1', name: 'GOLD'}); // the result of this `axios` call inside `useFetch` (in Hooks.js below), is exactly the same as the commented `const` line below - which would work just fine for table item rendering, ie when testing with a JSON array of 3 table items.

// const tradeData = [{"class":"demoCommodity","description":"really fabulous gold","fcn":"demoCreate","id":"trade001","name":"GOLD","owner":"JOHAN.BRINKS","tradename":"GLD"},{"class":"org.example.trading.Commodity","description":"more fabulous gold","fcn":"demoCreate","id":"trade004","name":"GOLD","owner":"NED.SLIVOVITZ","tradename":"GLD"},{"class":"org.example.trading.Commodity","description":"absolutely fabulous gold","fcn":"demoCreate","id":"trade005","name":"GOLD","owner":"ED.GOLDBERG","tradename":"GLD"}]

    // Setting state
    const [trades, setTrades ] = useState(tradeData); // this is the line with the issue
    console.log("trades in App is set to " + JSON.stringify(trades)); // `trades` is empty [] but `tradeData` has data, being evaluated later perhaps?
    const initialFormState = { id: '' , name: '', tradename: '' }; // not using all fields in form fyi
    const [ currentTrade, setCurrentTrade ] = useState(initialFormState)
    const [ editing, setEditing ] = useState(false)

    // CRUD operations
    const addTrade = trade => {
        trade.id = trades.length + 1
        setTrades([ ...trades, trade ])
    }

    const deleteTrade = id => {
        setEditing(false)

        setTrades(trades.filter(trade => trade.id !== id))
    }

    const updateTrade = (id, updatedTrade) => {
        setEditing(false)

        setTrades(trades.map(trade => (trade.id === id ? updatedTrade : trade)))
    }

    const editRow = trade => {
        setEditing(true)

        setCurrentTrade({ id: trade.id, name: trade.name, tradename: trade.tradename })
    }

    return (
        <div className="container">
            <h1>Trading App CRUD-style</h1>
            <div className="flex-row">
                <div className="flex-large">
                    {editing ? (
                        <Fragment>
                            <h2>Edit trade</h2>
                            <EditTradeForm
                                editing={editing}
                                setEditing={setEditing}
                                currentTrade={currentTrade}
                                updateTrade={updateTrade}
                            />
                        </Fragment>
                    ) : (
                        <Fragment>
                            <h2>Add trade</h2>
                            <AddTradeForm addTrade={addTrade} />
                        </Fragment>
                    )}
                </div>
                <div className="flex-large">
                    <h2>View trades</h2>
                    <TradeTable trades={trades} editRow={editRow} deleteTrade={deleteTrade} />
                </div>
            </div>
        </div>
    )
}

export default App

Hooks.js

import React, { useState, useEffect } from "react";
import axios from 'axios'

const useFetch = (httpurl, options) => {
const [mydata, setData] = useState([]);

  useEffect(() => {
    async function fetchData() {
       const response = await axios({
              method: 'POST',
              url : httpurl,
              headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json'
              },
              data: options
      });
      setData(response.data);  // what comes back is set to a JS variable called 'data'
    }
    fetchData();
  }, [httpurl]);

   return mydata;
};

export { useFetch };

tables / TradeTable.js

import React from 'react'

// this is where the App will process `trades` and process/render to view in a table, then take a CRUD action etc.

const TradeTable = props => (
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Tradename</th>
        <th>Trade Actions</th>
      </tr>
    </thead>
    <tbody>
      {props.trades.length > 0 ? (
        props.trades.map(trade => (
          <tr key={trade.id}>
            <td>{trade.name}</td>
            <td>{trade.tradename}</td>
            <td>
              <button
                onClick={() => {
                  props.editRow(trade)
                }}
                className="button muted-button"
              >
                Edit
              </button>
              <button
                onClick={() => props.deleteTrade(trade.id)}
                className="button muted-button"
              >
                Delete
              </button>
            </td>
          </tr>
        ))
      ) : (
        <tr>
          <td colSpan={3}>No trades</td>
        </tr>
      )}

那么,如何确保trades[]的调用数据中填充axios并代表新的State?特别是,“查看交易”的位置进一步向下App.js

非常感谢您提供任何指导!

1 个答案:

答案 0 :(得分:1)

摘自useState文档:

  

initialState参数是初始渲染期间使用的状态。   在随后的渲染中,将忽略它。

App的初始呈现期间,tradeData是一个空数组,因为尚未完成提取。 tradeData仅用作useState的initialState参数。

随后,当获取完成并且tradeData保留了获取的数据时,tradeData的更新值不会复制到trades状态变量中。

您可以使用效果将已加载的tradeData复制到trades

useEffect(() => {
    setTrades(tradeData)
}, [tradeData]);