I'm new to React Hooks and I'm unable to fix a State issue. I've read elsewhere on Stack Overflow about the asynchronous nature of useState/useEffect and it seems that whatever I try, including async/await, I cannot assign the JSON array results to my [data, callback] to render elements of the returned data in a simple table in my main App(.js) - see below. I've got an App.js, a Hooks.js and a Tradetable.js where the table of elements is populated (and the latter two files are imported inside 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>
)}
So - how to ensure that trades[] is populated from the data coming from the axios call and represents the new State ? In particular, the 'View trade' bit further down App.js
much appreciated in advance for any guidance!
tradeDatatoTradeTable? as in the code you have shared there isn't any mention of how you are usingTradeTable. - AdarshApp.js- check out the<h2>View trades</h2>section. - Paul O'Mahony