Ravshanbek Alijonov
Ravshanbek Alijonov

Reputation: 11

Too many Re-renders React JS

Can anyone tell me what is wrong with this code pls ?

    import React, { useState } from "react";

const Createcolumn = () => {
  const [sum, setSum] = useState('');
  const [dailySum, setDailySum] = useState(0);
  const [daysOfWork, setDaysOfWork] = useState(0);
  const [fare, setFare] = useState(0);
  const dailySumHandler = (e) => {
    setDailySum(Number(e.target.value));
  };

  const daysOfWorkHandler = (e) => {
    setDaysOfWork(Number(e.target.value));
  };

  const fareHandler = (e) => {
    setFare(Number(e.target.value));
  };

  setSum(dailySum * daysOfWork + fare);

  return (
    <div>
      <div className="column">
        <h1>Name</h1>
        <h1>Daily</h1>
        <h1>Days of Work</h1>
        <h1>Fare</h1>
        <h1>Total</h1>
      </div>
      <div className="column">
        <div>
          <h1>Nodirbek</h1>
        </div>
        <div>
          <input type="text" onChange={dailySumHandler} />
        </div>
        <div>
          <input type="text" onChange={daysOfWorkHandler} />
        </div>
        <div>
          <input type="text" onChange={fareHandler} />
        </div>
        <div>
          <h1>{sum}</h1>
        </div>
      </div>
    </div>
  );
};

export default Createcolumn;

I cannot set my Sum to h1, it is saying too much render I tried to make a function as well, but it doesn't work either

I cannot set my Sum to h1, it is saying too much render I tried to make a function as well, but it doesn't work either

Upvotes: 0

Views: 470

Answers (6)

Vivick
Vivick

Reputation: 4991

This is typically the kind of scenario you want to use useMemo to solve:

import { useMemo } from "react"

const sum = useMemo(
    () => dailySum * daysOfWork + fare,
    [dailySum, daysOfWork, fare]
);

This allows you to automatically recompute the sum whenever any of its components changes without having to keep track of an additional state and setter.

Upvotes: 0

Louay Al-osh
Louay Al-osh

Reputation: 3405

The why: You're changing the state in every render not based on some change in your component, remember how react works: you change the state => react re-render your component all over again.

At every render you tell react to change the state(setSum(...)) which will tell react to re-render, all over again, it enters a loop of render and a call to setSum which cause a re-render forever.

Solution: Don't use state if your data can be computed based on other states, it looks like the sum only depends on other states, why create a state for it if you can calculate it easily from other states?

Delete the line:

  const [sum, setSum] = useState('');

and just add the line(before the return statement)

  let sum = (dailySum * daysOfWork + fare);

Upvotes: 0

user15393979
user15393979

Reputation:

You have to use arrow function notation while calling those functions and pass the event that's what's causing re-renders.

Your code:

 </div>
        <div>
          <input type="text" onChange={dailySumHandler} />
        </div>
        <div>
          <input type="text" onChange={daysOfWorkHandler} />
        </div>
        <div>
          <input type="text" onChange={fareHandler} />
        </div>

Fix:

 </div>
        <div>
          <input type="text" onChange={(e) => dailySumHandler(e)} />
        </div>
        <div>
          <input type="text" onChange={(e) => daysOfWorkHandler(e)} />
        </div>
        <div>
          <input type="text" onChange={(e) => fareHandler(e)} />
        </div>

Upvotes: 0

Nick Vu
Nick Vu

Reputation: 15510

The problem is you're calling this directly into your render

setSum(dailySum * daysOfWork + fare);

Once setSum gets triggered, it will cause UI re-rendering which calls render function again. And again setSum will continue being called (it's like deadlock)

Here is a possible fix

import React, { useState } from "react";

const Createcolumn = () => {
  const [dailySum, setDailySum] = useState(0);
  const [daysOfWork, setDaysOfWork] = useState(0);
  const [fare, setFare] = useState(0);
  const dailySumHandler = (e) => {
    setDailySum(Number(e.target.value));
  };

  const daysOfWorkHandler = (e) => {
    setDaysOfWork(Number(e.target.value));
  };

  const fareHandler = (e) => {
    setFare(Number(e.target.value));
  };

  return (
    <div>
      <div className="column">
        <h1>Name</h1>
        <h1>Daily</h1>
        <h1>Days of Work</h1>
        <h1>Fare</h1>
        <h1>Total</h1>
      </div>
      <div className="column">
        <div>
          <h1>Nodirbek</h1>
        </div>
        <div>
          <input type="text" onChange={dailySumHandler} />
        </div>
        <div>
          <input type="text" onChange={daysOfWorkHandler} />
        </div>
        <div>
          <input type="text" onChange={fareHandler} />
        </div>
        <div>
          <h1>{dailySum * daysOfWork + fare}</h1>
        </div>
      </div>
    </div>
  );
};

export default Createcolumn;

Upvotes: 2

Icekid
Icekid

Reputation: 505

The problem here is that when you try to use setstate() before you bring in the return() statement it will bring out that error. The solution is that the setSum() have to fire after the first render after the return statement

Upvotes: -1

Tim R. Jensen
Tim R. Jensen

Reputation: 157

You can't use calls to hook setters in the body of the function, it'll cause a rerender, which will cause a rerender, which will cause rerender, and so and so forth.

Instead initialize your value when you call the hook: const [sum, setSum] = useState(dailySum * daysOfWork + fare);

Upvotes: 0

Related Questions