Home > Enterprise >  React SetState not working till second render if HTML element updated inside a function
React SetState not working till second render if HTML element updated inside a function

Time:05-01

I am working on a useState example, and I am finding that it doesn't work until the second render. The first time around it holds the default value of 0.

import React, { useState } from "react";

const MyState = () => {
  const [age, setage] = useState(0);

  function handleClick() {
    var enteredAge = document.getElementById("txtAge").value;
    if (enteredAge) {
      setage(enteredAge);
      if (enteredAge > 50) {
        document.getElementById("lblResult").innerText = "Wow "   age   "! You're old, rest up!";
      } else {
        document.getElementById("lblResult").innerText = "Wow "   age   "! Young gun!";
      }
    }
  }

  return (
    <div>
      Enter Your Age:
      <input type="text" id="txtAge" name="age" />
      <button onClick={handleClick}> Check </button>
      <label id="lblResult"></label>
    </div>
  );
};

export default MyState;

If I do something like the following, this works fine on every render. But if I use setState inside the function like I showed above, then the age inside the innerText still holds old value. Why is that, and what the right way to do this?

<label id="lblResult">{age}</label>

CodePudding user response:

You should not mutate the DOM node directly, since react maintains the V-DOM and mutations you are doing to lblresult will be lost after re-render. The right way is to use the state value and conditionally render the data.

import React, { useState } from 'react';

const MyState = () => {
  const [age, setage] = useState(0);

  function handleClick() {
    var enteredAge = document.getElementById('txtAge').value;
    if (enteredAge) {
      setage(enteredAge);
    }
  }

  return (
    <div>
      Enter Your Age:
      <input type="text" id="txtAge" name="age" />
      <button onClick={handleClick}> Check </button>
      <label id="lblResult">
        {age > 50
          ? `"Wow ${age}! You're old, rest up!`
          : `Wow ${age}! Young gun!`}
      </label>
    </div>
  );
};

export default MyState;

Update:

As Bjorn mentioned, You could use refs instead of getElementById to get the input field value. Ref is a Object with persistent reference between re-render, the current property of the ref holds the DOM node.

import React, { useState, useRef } from 'react';

const MyState = () => {
  const [age, setage] = useState(0);
  const inputRef = useRef(null);

  function handleClick() {
    var enteredAge = inputRef.current.value;
    if (enteredAge) {
      setage(enteredAge);
    }
  }

  return (
    <div>
      Enter Your Age:
      <input type="text" id="txtAge" name="age" ref={inputRef} />
      <button onClick={handleClick}> Check </button>
      <label id="lblResult">
        {enteredAge > 50
          ? `"Wow ${age}! You're old, rest up!`
          : `Wow ${age}! Young gun!`}
      </label>
    </div>
  );
};

export default MyState;
  • Related