I'm attempting to create a data table with react hooks but I keep getting duplicates rows in my state. Here is the call where I'm getting values doing some manipulation and then calling my function to update state:
var tableRowIndex = 0;
const CoinTable = () => {
const baseURL = 'endpoint/';
const [tableRows, setRows] = useState([] as any);
const getCurrentPrice = async (inputs: any) => {
const response = await axios.get(`${baseURL}${inputs.currency}/USD`)
let currentPrice = response.data
inputs.cryptoPrice = currentPrice.rate;
let coinsRequired = inputs.amount / inputs.cryptoPrice;
inputs.amtCrypto = coinsRequired.toFixed(8);
addNewRow(inputs)
}
Here is my function where I'm attempting to update state
const addNewRow = (inputs: any) => {
tableRowIndex
inputs.index = tableRowIndex
setRows([...tableRows, inputs])
}
This is the rest of the components where I'm mapping through my rows and outputting in my JSX.
const rows = tableRows.map((row: any) => {
return (
<TableRow
key={tableRowIndex}
addNewRow={addNewRow}
removeRow={removeRowHandler}
getCurrentPrice={getCurrentPrice}
row={row}
/>
)
})
return (
<>
<AddItem
getCurrentPrice={getCurrentPrice}
/>
{tableRows.length > 0 &&
<table>
<tbody>
<tr>
<th>Merchant</th>
<th>Item</th>
<th>Amount(Crypto)</th>
<th>Currency</th>
<th>Price/crypto(USD)</th>
<th>Amount(USD)</th>
</tr>
{rows}
</tbody>
</table>
}
</>
)
}
export default CoinTable;
Inputs is object containing user inputs to be rendered as a new row. It appears to be an issue as to how I'm updating state using the spread operator but I'm not sure.
CodePudding user response:
It appears as though you are using the single tableRowIndex
"global" value as the React key for every mapped element. You likely meant to use the row
indexgenerated in
addNewRowwhen adding an element to the
tableRows` state.
const addNewRow = (inputs: any) => {
tableRowIndex ;
inputs.index = tableRowIndex; // <-- assigned here
setRows([...tableRows, inputs]);
}
...
const rows = tableRows.map((row: any) => {
return (
<TableRow
key={row.index} // <-- used here
addNewRow={addNewRow}
removeRow={removeRowHandler}
getCurrentPrice={getCurrentPrice}
row={row}
/>
)
})
A more idiomatic method would be to call this augmented property id
so it's abundantly clear it's not any array index and actually a unique value assigned to each element. I'd even go as far as to say you might want to use a library that generates GUIDs for you. uuid is a great one.
import { v4 as uuidV4 } from 'uuid';
...
const addNewRow = (inputs: any) => {
setRows(rowData => [
...rowData,
{
...inputs, // <-- don't mutate inputs object
id: v4uuid() // <-- assign unique id
},
]);
}
...
const rows = tableRows.map((row: any) => {
return (
<TableRow
key={row.id}
addNewRow={addNewRow}
removeRow={removeRowHandler}
getCurrentPrice={getCurrentPrice}
row={row}
/>
)
})