TolgaKmbl
TolgaKmbl

Reputation: 17

React useEffect and useState problems

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

Answers (2)

Giorgi Gvimradze
Giorgi Gvimradze

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

Giovanni Esposito
Giovanni Esposito

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

Related Questions