1

Code

PrizeHistory.js

...

const PrizeHistory = () =>  {
  const [history, setHistory] = useState([]);

  useEffect(() => {

    async function getHistory () {
      try {
        let result = await sqliteInterface.getAllPrizes(db, prizeTable);
        result == null ? console.log("res is null") : setHistory(result);
        console.log("result" + result);
        console.log("history" + history);
      } catch (err) {
        console.log(err);
      }
    }

    getHistory();
  }, [history])

  return (
    <View style={styles.body}>
      <Text style={styles.text}>Prize History</Text>
    </View>
  );
}

getAllPrizes

getAllPrizes(db, tableName) {
    return new Promise((resolve, reject) => {
      db.transaction((tx) => {
        tx.executeSql(
          `SELECT * FROM ${tableName};`, 
          [],
          (tx, res) => {
            let len = res.rows.length;
            let results = [];  

            if(len > 0) {
              for(i = 0; i < res.rows.length; i++) {
                results.push(res.rows.item(i));
              }
            } 
            console.log("resolving promise now");
            resolve(JSON.stringify(results));
          },
          (error) => {
            reject(Error(`SQLite getAllPrizes: failed to get '*' from ${tableName}: ` + error));
          }
        );
      }); 
    });
  }

The goal

When the page is mounted, set the history state to the data in the database. I initially tried this:

  useEffect(() => {

    async function getHistory () {
      try {
        let result = await sqliteInterface.getAllPrizes(db, prizeTable);
        result == null ? console.log("res is null") : setHistory(result);
        console.log("result" + result);
        console.log("history" + history);
      } catch (err) {
        console.log(err);
      }
    }

    getHistory();
  }, [])

but it never set my history variable correctly. I just got an empty array (which is what I inistially set the history state to). I expected the history variable to be equal to the result variable in the history console.log(), but it's not.

So I changed the useEffect() to this:

  useEffect(() => {

    async function getHistory () {
      try {
        let result = await sqliteInterface.getAllPrizes(db, prizeTable);
        result == null ? console.log("res is null") : setHistory(result);
        console.log("result" + result);
        console.log("history" + history);
      } catch (err) {
        console.log(err);
      }
    }

    getHistory();
  }, [history])

This code changes the history variable correctly, but I expected it to go into an infinite loop... but it didn't? Here's my logic

  1. useEffect() has [history] as dependency
  2. onMount, history is set to default value of []
  3. useEffect() sees history is set and begins running
  4. useEffect() resets history
  5. useEffect() should start again because it reset the history variable itself
  6. Repeat 3-5 infinitely...

But it does not repeat infinitely...

My Questions

  1. Why is useEffect() not running infinitely when [history] is set as its dependency
  2. Why is useEffect() not setting my history variable correctly on mount when it has [] as it's dependency.
1
  • Why do you expect useEffect() to run infinitely. "History" is a state variable. shouldn't it be executed only when the variable "history" is updated? Commented Dec 30, 2021 at 19:46

2 Answers 2

2

The answer to your 1 question is: history does not change after first set because your getAllPrizes returns always the same value so the useEffect is triggered only once (on mount).

For the 2 question, the problem is that you are trying to log the history value right after a call to setHistory, which is async. If you want to log history each time it is updated you have to do something like:

useEffect(() => {
  console.log(history)
}, [history])
Sign up to request clarification or add additional context in comments.

4 Comments

that makes sense for question 1. For question 2, the useEffect() has console.log("result" + result); and console.log("history" + history);. the second log prints out empty.
Ok, now is clear. history is empty because setHistory is async, so the history is not updated right after a call to setHistory. If you want to log the value of history each time it is updated you have to put a console.log inside a useEffect with a dep array [history].
You're right. Thanks so much
@KraveXL glad I was helpful. If the answer solves your problem consider to mark it as accepted in order to help other people to find the solution quickly. Thanks.
0

Are you sure you are not trying to set a string type on this line:

result == null ? console.log("res is null") : setHistory(result);

As far as I see initial type is an array and the resolve function returns a stringified object. Do you get any warnings in the console?

1 Comment

Yes you are right. I already realized this and was planning to fix it once I got the variable set correctly. I can change the variable type for a state at any time. I initially set history to an array as a test. Thanks for pointing this out though

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.