-3

I have a state variable that should be updated when the condition is met, but whenever it makes it inside the if statement the index is always 0.


import React, { useState, useEffect } from 'react';
import { words } from "./words.json";
import TypingTest from './components/TypingTest';
import './App.css';

function App() {

  const [index, setIndex] = useState(0);

  const onKeyPress = (event) => {
    console.log("Current key: ", event.key);

    switch (event.key) {
        

        default:
        if(event.key === words[index]){
          setIndex((index) => index + 1);
          console.log("New index: ", index);
        }else{
          console.log('Wrong' , words[index]);
        }
        break;
        }
    };

  useEffect(() => {
    document.addEventListener('keydown', onKeyPress);

    return () => {
      document.removeEventListener('keydown', onKeyPress);
    };
  }, [])

  return (
    <div className="App">
      <header className="App-header">
        <TypingTest words={words} index={index}/>

      </header>
    </div>
  );
}

export default App;

Here is console output

Current key:  L
New index:  0
Current key:  L
New index:  0
Current key:  L
New index:  0
Current key:  L
New index:  0
Current key:  L
New index:  0

2 Answers2

0

First of all, when you run setIndex((index) => index + 1) you're updating the state but your locally scoped index constant will remain the same value as before (since it's a constant, it couldn't even be assigned a new value). That's why on the next line you log the same value.
Your change to the state will be reflected the next time React runs your function component and you get the new value in that scope through const [index, setIndex] = useState(0).

Secondly, while you define a new onKeyPress handler function each time your function component runs, you only add this as an event handler the first time it runs and that's why it always logs the initial value of your state variable.
The reason for this is that you pass an empty dependency array to useEffect. This means that the effect will only run when the component is first mounted and the cleanup will only run when it is unmounted. What you want is for the effect and cleanup to run every time your index constant changes so that the event handler always gets replaced by the new one you defined, which has the updated value of the state in its scope. The most appropriate way to accomplish that is to pass index as a dependency to useEffect, i.e. [ index ] instead of [].

So, to summarize:

  1. You can't expect console.log("New index: ", index) to log the new value because the locally scoped index constant is not the thing you updated
  2. Add index as a dependency for useEffect so that the event handler always gets updated when necessary
Lennholm
  • 7,205
  • 1
  • 21
  • 30
-1

Put [onKeyPress] as dependency array to useEffect

useEffect(() => {
    document.addEventListener('keydown', onKeyPress);

    return () => {
      document.removeEventListener('keydown', onKeyPress);
    };
}, [onKeyPress])
jkaczmarkiewicz
  • 1,500
  • 6
  • 17