简体   繁体   中英

React Too Many re-renders error when trying to change the state of a variable

I am not sure why I am getting this error, I have been looking online to find an answer but I cannot seem to figure it out. The error is coming from when I am trying to change the state of a state variable when the key 'Enter' is pressed. I am still new to react so any help would be greatly appreciated!!

Here is the error message

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
  20 |      
  21 |      case "Enter":
  22 |        if(timerState === false){
> 23 |          setTimerState(true);
     | ^  24 |        }
  25 |          break;
  26 | 

Here is the file in question

import React, { useState, useEffect } from 'react';
import { words } from "./words.json";
import TypingTest from './components/TypingTest';
import SignInModal from './components/SignInModal';
import TitleBar from './components/TitleBar';
import Timer from './components/Timer';
import './App.css';
import { ThemeProvider } from 'styled-components';

function App() {

  const [index, setIndex] = useState(0);
  const [showSignIn, setShowSignIn] = useState(false);
  const [timerState, setTimerState] = useState(false);

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

    switch (event.key) {
            
      case "Enter":
        if(timerState === false){
          setTimerState(true);
        }
                break;

      case "Backspace":
        break;

            default:
        if(event.key === words[index]){
          setIndex((index) => index + 1);
        }
                break;
        }
    };

  const openSignIn = () => {
    setShowSignIn(prev => !prev);
  };

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

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

  return (
    <div className="App">
      <TitleBar openSignIn={openSignIn} />
      <header className="App-header">
      </header>
      <div className="landing">
        {/* <Timer /> */}
        <TypingTest timerState={timerState} words={words} index={index}/>
        <button onClick = {() => setIndex(0)}>reset</button>
        <SignInModal showSignIn={showSignIn} setShowSignIn={setShowSignIn} />
      </div>
    </div>
  );
}

export default App;

First of all you have to turn off your useEffect . Occur only once. You can access your current state value within setState

setState(currentState => {
    return currentState;
});

The keydown , and keypress , and keyup events cause the component to re-render

I know a solution to this problem, but I'm not sure it is the main solution, but it solves the problems

You can define your states inside useEffect as a variable and change their value

useEffect(() => {
    let timerState;
    const onKeypress = (e) => {
        // do anything
    }

    document.addEventListener("keypress", onKeypress);

    return () => {
        document.removeEventListener("keypress", onKeypress);
    }
}, []);

Adding a listener inside a useEffect which has dependencies means any time those variables in the dependency array change, you are adding another listener. To set a listener when the component mounts, put the addEventListener method in a useEffect that has an empty (or no) dependency array.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM