Reputation: 17
I am trying to create a simple React front-end for a smart contract which is a To-Do List. My problem is with the useEffect
hook. I am trying to do a for loop inside the effect hook, and putting the results into the toDoTask state. While I managed to print my results on screen, they do not show on the console (shows an empty array like the initial value). And when I try to add the todoTask state as a dependency (to check the changes, when I add new tasks), the loop goes infinite. I don't know what is the problem actually, here is the code:
function App() {
const [todoTask, setTodoTask] = useState([]);
const [web3, setWeb3] = useState(undefined);
const [accounts, setAccounts] = useState(undefined);
const [contract, setContract] = useState(undefined);
const [taskCount, setTaskCount] = useState(0);
// HERE I HAVE HAD ANOTHER EFFECT HOOK TO CONNECT BLOCKCHAIN, I'VE REMOVED IT FOR SIMPLICITY
useEffect(() => {
const todoInit = async () => {
const taskCount = await contract.methods.taskCount().call();
setTaskCount(taskCount);
for (var i = 1; i <= taskCount; i++) {
const task = await contract.methods.tasks(i).call();
setTodoTask(prevArray => [...prevArray, task.content]); // task is an object, i'm getting the content(text basically)
}
console.log(taskCount); // This works fine
console.log(todoTask); // This returns an empty array
}
if(typeof web3 !== 'undefined' && typeof accounts !== 'undefined' && typeof contract !== 'undefined') {
todoInit();
}
}, [web3, accounts, contract])
Upvotes: 1
Views: 250
Reputation: 2129
I do not see the need of using taskCount
as a state. Could it be just a variable? Meaning of removingconst [taskCount, setTaskCount] = useState(0);
the function could look this way:
useEffect(() => {
const todoInit = async () => {
const tasks = await contract.methods.taskCount().call();
tasks.map(async (element, index) => {
const task = await contract.methods.tasks(index).call();
setTodoTask((prevArray) => [...prevArray, task.content]); // task is an object, i'm getting the content(text basically)
});
console.log(tasks); // This works fine
};
if (
typeof web3 !== "undefined" &&
typeof accounts !== "undefined" &&
typeof contract !== "undefined"
) {
todoInit();
}
}, [web3, accounts, contract]);
useEffect(() => {
console.log(todoTask);
}, [todoTask]);
Also, if the reason behind having this condition if(typeof web3 !== 'undefined' && typeof accounts !== 'undefined' && typeof contract !== 'undefined')
- is to run only once, then you could use it like empty array ,[])
in the end and get rid of the checking undefined
types.
You can check how to run useEffect
only once, here
Upvotes: 1
Reputation: 11156
You can't log a state variable just setted because setTodoTask
is async.
Much better use another useEffect
:
useEffect(() => {
console.log(todoTask);
}, [todoTask]);
This should log the very last value of todoTask
.
Note: the fact that console.log(taskCount);
works fine it's just a case (maybe due to the fact that for
takes a lot of time and setTaskCount
will be resolved before).
Upvotes: 0