1

I ran into an issue where some logic within useEffect runs on mount once before a state update within it is triggered. Example below:

function App() { 

const [account, setAccount] = useState("0x123");

useEffect(() => {

async function main() {
  let fetchedAccount = await //some fetch logic to get new account

  setAccount(fetchedAccount);
}

console.log(account);
let result = await someFunction(account);
}

I realized when running this, my App runs the logic with the predefined state i.e. someFunction("0x123") before running someFunction("updated state from fetchedAccount"). So console.log(account) shows "0x123" once and then once more for the fetchedAccount string.

How can I avoid this behavior and just have the useEffect run someFunction(accounts) after setAccount(fetchedAccount) is done?

Previously when it was a class component, I used this.setState to update the 'account' state and the someFunction(this.state.account) worked correctly. It doesn't run with the predefined state and only runs with the updated value after this.setState.

Thanks in advance!

  • What's preventing you from using `fetchedAccount` with `someFunction` ? Meaning, simply: `someFunction(fetchedAccount)` (inside `main`)? – Yoshi Jul 01 '21 at 07:55
  • thanks @Yoshi, you're right. Nothing is preventing me from doing that. But when I tried to console.log(account) within main it still shows "0x123" and another log for the updated fetchedAccount. Main thing is I am trying to avoid someFunction to run with "0x123" as it will run into an error unless its a valid account. User Hyetigran below suggested adding a conditional to only run someFunction if account is not undefined. That way on the first mount, someFunction would not run if its set as undefined, then only when setAccount(fetchedAccount) updates the state, someFunction will run. – hungryhungrydev Jul 01 '21 at 08:26
  • I understand, and yes I'd advice the same. Use some value you can identify as "no data"; `undefined` or `null` are typical candidates. To understand why `console.log(account);` logs the *old* value, you need understand ["How do JavaScript closures work?"](https://stackoverflow.com/q/111102/697154) and then why this is relevant to this typical react example ([here](https://stackoverflow.com/a/58877875/697154) or [here](https://stackoverflow.com/a/68189774/697154)). – Yoshi Jul 01 '21 at 08:34
  • Thanks @Yoshi! the links to closure really helped! And the conditional approach worked :) appreciate your inputs! – hungryhungrydev Jul 03 '21 at 02:02

1 Answers1

0

Try adding another useEffect hook that includes 'account' in the dependency array.

useEffect(() => {
 if(account !== "0x123"){
  let result = await someFunction(account);
 }
}, [account])

This should ensure that someFunction will only run if value of account changes.

edit: hmm, would adding a conditional to check that account is not "0x123" fix your issue?

Also, you could set initial state to undefined.

Hyetigran
  • 1,150
  • 3
  • 11
  • 29
  • Hey @hyetigran, thanks for the suggestion! Hmm I just tried it and it still triggered the first predefined state. I believe adding the second argument means that someFunction will be triggered both on first mount and also if 'account' changes. (Example 3 in this example here) https://stackoverflow.com/questions/55240526/useeffect-second-argument-variations-in-react-hook – hungryhungrydev Jul 01 '21 at 07:43
  • 1
    maybe i'll give a bit more background of what the app is trying to do to help. It's actually a dApp that's reading a user's Metamask account when they connect to the dApp. Once it is connected, it is supposed to get the user's account and run someFunction on it. Conditional check sounds doable! If I got you right, you're suggesting to set an initial account of say 'undefined', and have useEffect only run someFunction if the account is not undefined? That way once setAccount is triggered and updates the account, someFunction will run since it is no longer undefined. – hungryhungrydev Jul 01 '21 at 08:15
  • @hungryhungrydev try that and let me know if it works – Hyetigran Jul 01 '21 at 08:28
  • the conditional worked! Thanks a bunch! accepting as answer – hungryhungrydev Jul 03 '21 at 02:01