useState does not work as expected

Asked

Viewed 362 times

1

I want to do a simple mathematical operation from two random numbers when I click on the button, however, every time I click on the button the result shown on screen is from the previous operation and I can’t leave it correct.

Example:

Resultado 1 -> 2 + 2 =  0;
Resultado 2 -> 3 + 5 =  4;
Resultado 3 -> 5 + 5 =  8;
Resultado 4 -> 2 + 6 = 10;

import React, { useState } from "react";
import * as math from "mathjs";
import "./styles.css";

export default function Card() {
  const [number1, setNumber1] = useState(0);
  const [number2, setNumber2] = useState(0);
  const [operation, setOperation] = useState("");
  const [result, setResult] = useState(0);

  function handleSubmit() {
    // Gera valores aleatórios para os números de 0 a 10
    setNumber1(parseInt(Math.random() * (11 - 0) + 0));
    setNumber2(parseInt(Math.random() * (11 - 0) + 0));
    // Cria uma string com a operação completa
    setOperation(`${number1}+${number2}`);
    // Define o resultado a partir da string
    setResult(math.evaluate(operation));
  }
  return (
    <div className="card">
        <h1>Treino de cálculo</h1>
        <h2>
            {operation} = {result}
        </h2>
        <input type="number" placeholder="Sua resposta" />
        <button onClick={() => handleSubmit()}>
            Verificar resposta
        </button>
    </div>
  );
}

2 answers

2


The component state updates are not as simple as they seem, they are asynchronous, in short it takes a while to happen and the variables with the new states need to be monitored to make some decision, in their code basically to work:

function Card() {
  const [number1, setNumber1] = React.useState(0);
  const [number2, setNumber2] = React.useState(0);
  const [operation, setOperation] = React.useState("");
  const [result, setResult] = React.useState(0);

  function random() {
    return parseInt(Math.random() * (11 - 0) + 0);
  }
  React.useEffect(() => {
    setOperation(`${number1}+${number2}`);    
  },[number1, number2]);
  React.useEffect(() => {
    setResult(state => number1 + number2);
  }, [operation]);
  function handleSubmit() {    
    setNumber1(state => random());
    setNumber2(state => random());    
    
  }
  return (
    <div className="card">
        <h1>Treino de cálculo</h1>
        <h2>
            {operation} = {result}
        </h2>
        <input type="number" placeholder="Sua resposta" />
        <button onClick={() => handleSubmit()}>
            Verificar resposta
        </button>
    </div>
  );
}

ReactDOM.render( <Card/> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root">Carregando ...</div>

in this example waits to change the state of the two variables: number1 and number2 then update the variable operation and finally show all the results, IE, has a logical sequence of update to work.

There is a way much better and for me more reliable, example:

function Card() {
  const [data, setData] = React.useState({
    number1: 0,
    number2: 0
  });  
  const [result, setResult] = React.useState({
    operation: '', 
    result: 0
  });
  function random() {
      return parseInt(Math.random() * (11 - 0) + 0);
  }
  function handleSubmit() {    
    const number1 = random();
    const number2 = random();
    setData({number1, number2});      
  }
  React.useEffect(() => {
    const { number1, number2 } = data;
    const operation = `${number1} + ${number2}`;
    const result = number1 + number2;
    setResult({
      operation,
      result
    });    
  }, [data]);
  return (
    <div className="card">
        <h1>Treino de cálculo</h1>
        <h2>
            {result.operation} = {result.result}
        </h2>
        <input type="number" placeholder="Sua resposta" />
        <button onClick={() => handleSubmit()}>
            Verificar resposta
        </button>
    </div>
  );
}

ReactDOM.render( <Card/> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root">Carregando ...</div>

in this second form is created an object and when this object is changed, I change the result object is easier to control the changes and sequence of the state variables.

  • Thanks Virgilio, as I am still learning There are things there that I have no idea what hahah is, but I will take a good look and study the code. When complete I will put on my github :D. Thank you very much!

  • @Yagojuan if useful tick as answer !

  • Well again I received a negative vote, I do not know the reasons that led to this, I believe it is persecution. I do not know what to do!

  • Virgilio, I got it with your first code, I just had to make a few minor changes to fit better into my project. Thank you so much for your help. I marked it as a response

0

I believe that if you put a useEffect to perform the function when mounting the components solve your problem:

import React, {useState, useEffect} from "react";
import "./styles.css";
import * as math from "mathjs";

export default function Card() {
  const [number1, setNumber1] = useState(0);
  const [number2, setNumber2] = useState(0);
  const [operation, setOperation] = useState("");
  const [result, setResult] = useState(0);

  useEffect(() => {
    handleSubmit();
  },[])

  function handleSubmit() {
    // Gera valores aleatórios para os números de 0 a 10
    setNumber1(parseInt(Math.random() * (11 - 0) + 0));
    setNumber2(parseInt(Math.random() * (11 - 0) + 0));

    // Cria uma string com a operação completa
    setOperation(`${number1}+${number2}`);

    // Define o resultado a partir da string
    setResult(math.evaluate(operation));
  }

  return (
    <div className="card">
      <h1>Treino de cálculo</h1>
      <h2>
        {operation} = {result}
      </h2>
      <input type="number" placeholder="Sua resposta" />
      <button onClick={() => handleSubmit()}>Verificar resposta</button>
    </div>
  );
}
  • also falls in the same response of another companion, already explain and reinforce the updates are asynchronous, IE, are not sequential so will not work.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.