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!
tradeData
toTradeTable
? 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