I can’t read the values that I am pushing into my array in React. I am using a useCallback() hook to populate an array with values from an asynchronous call (web3 events). I am doing this because I don’t want to use setState() method multiple times over to re-render my component. Instead I want to populate one array and pass that into my setState(). I am new to React and programming in general, let me know if I made a silly mistake.
When I try to console.log() ‘arr’ in the useEffect() I get an array that look like the picture, but I can’t access arr[0], or arr1 its just undefined.
enter image description here
import React, { useState, useEffect, useMemo, useContext, useCallback } from "react";
import { useTable } from 'react-table';
import { DAOContext } from '../pages/index.jsx';
import Vote from './Vote.jsx';
import ExecuteProposal from "./ExecuteProposal";
import Countdown from "./Countdown.jsx"
import VoteState from "./VoteState.jsx"
function VotingTable(){
const[proposals, setProposals] = useState([]);
const[votes, setVotes] = useState([]);
const[updated, setUpdated] = useState(1);
const {web3} = useContext(DAOContext);
const {accounts} = useContext(DAOContext);
const {contract} = useContext(DAOContext);
const {connectedAddress} = useContext(DAOContext);
const {contractAddress} = useContext(DAOContext);
const {socketContract} = useContext(DAOContext);
const getProposals = useCallback(() => {
if (socketContract != undefined && connectedAddress != undefined){
var arr = new Array();
socketContract.events.proposalEdit({fromBlock:0}, function(error,event){
if (error){console.log(error)}
const newProposal = {"id":event.returnValues.id,
"name":event.returnValues.name,
"amount":event.returnValues.amount,
"recipient":event.returnValues.recipient,
"votes": event.returnValues.votes,
"executed":event.returnValues.executed ,
"end":event.returnValues.end
};
arr.push([newProposal]);
}
)
console.log(arr[1]);
return arr;
}
}, [socketContract,connectedAddress])
useEffect(() => {
const arr = [getProposals()];
const reactElementsArray = arr.map(proposal => {
console.log(proposal);
})
//console.log(reactElementsArray[0]);
})
/*
useEffect(() => {
if (socketContract != undefined && connectedAddress != undefined){
socketContract.events.emitVote({fromBlock:0}, function(error, event){
if (error){console.log(error)}
const newVote = {"ProposalId" :event.returnValues.proposalId,
"Sender": event.returnValues.sender
};
console.log(newVote);
if (votes.length == 0){
setVotes(votes => ([...votes, newVote]));
}
})
}
},[socketContract,connectedAddress])
*/
const votesData = useMemo(() => [...votes], [votes]);
//Apparently useMemo() is the only option here, not totally sure why jsut yet, should do more research on this...
//Setting up the Header & accessor for the columns information
const proposalsData = useMemo(() => [...proposals],[proposals]);
const proposalsColumns = useMemo(() => proposals[0] ? Object.keys(proposals[0]).filter((key) => key !== "rating").map((key) =>{
return {Header: key, accessor: key};
}) : [] , [proposals]);
//console.log(votesData);
const voteHooks = (hooks) => {
hooks.visibleColumns.push((columns) => [
...columns,
{ id:"Vote State",
Header: "Vote State",
Cell: ({row}) =>(<VoteState index ={row.id} value={votesData}/>),
},
{ id:"Countdown",
Header: "Time Remaining",
Cell: ({row}) =>(<Countdown futureTime={proposals[row.id]["end"]}/>),
},
{ id:"Vote Button",
Header: "Vote",
Cell: ({row}) =>(<Vote index={row}/>),
},
{ id:"Execute Button",
Header: "Execute",
Cell:({row}) =>(<ExecuteProposal index={row}/>),
},
]);
};
//Create a table instance with 'useTable()' from react-table
const tableInstance = useTable({columns: proposalsColumns, data:proposalsData}, voteHooks);
const {getTableProps, getTableBodyProps, headerGroups, rows, prepareRow} = tableInstance;
//console.log("proposals",proposals[0]);
//render the table information and populate with desired data
return(
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) =>(
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) =>{
prepareRow(row);
return <tr {...row.getRowProps()}>
{row.cells.map((cell,idx) => (
<td {...cell.getCellProps()}> {cell.render("Cell")} </td>
))}
</tr>
})}
</tbody>
</table>
</div>
)
}
export default VotingTable;