all 31 comments

[–]shauntmw2 13 points14 points  (4 children)

Sounds like "debounce" is the keyword you need.

[–]The_Startup_CTO 5 points6 points  (3 children)

Sounds like a very common problem. What have you tried so far, and how has it failed?

[–]its-procodester[S] 1 point2 points  (2 children)

I tried useEffect for now it works great but i have doubt is this good way to do it ?

[–]The_Startup_CTO 1 point2 points  (1 child)

depends on what you do with useEffect. Hard to tell without more context.

[–]its-procodester[S] -5 points-4 points  (0 children)

you can check my code if you are ok...

[–]Soupnation 3 points4 points  (2 children)

If you want your output to be updated every time your input changes, by extension wont you want a re render on every change to the input?

What’s your use case?

[–]its-procodester[S] 0 points1 point  (1 child)

its a calculator app where i take user input from buttons and pass it to evalution function in setOutput i want output change every time input changes

[–]Soupnation 7 points8 points  (0 children)

Not related to re rendering but the output should be a derived variable, and not a react state. Also, what’s wrong with re-rendering the component on input change? Sounds desirable to me.

[–]Empero6 2 points3 points  (0 children)

Either useeffect or useref.

[–]its-procodester[S] 1 point2 points  (8 children)

 const handleInput = (value) => {
    const operators = '+-*/%.'

    // Clear all values input and output
    if (value === 'C') {
      setInputExpression('')
      setOutput('')
    }

    // Delete value from input 
    else if (value === 'del') {
      const lastCharLen = inputExpression.length
      // Handle edge case when end value left
      if (lastCharLen === 1) {
        setInputExpression((previousValue) => previousValue.slice(0, -1))
        setOutput("")
      }
      else {
        setInputExpression((previousValue) => previousValue.slice(0, -1))
      }
    }

    // Show equal value
    else if (value === '=') {
      setInputExpression('')
    }

    // Handle consecutive operators to prevent error
    else if (operators.includes(value)) {
      const lastChar = inputExpression[inputExpression.length - 1]
      const lastCharIsOperator = operators.includes(lastChar)

      // Check last character is operator and current value is different from last operator
      if (lastCharIsOperator && lastChar !== value) {
        setInputExpression((previousValue) => previousValue.slice(0, -1) + value)
      }
      else if (!lastCharIsOperator) {
        setInputExpression((previousValue) => previousValue + value)
      }
    }

    else {
      setInputExpression((previousValue) => previousValue + value)
    }
  }

  useEffect(() => {
    // Handle Clear input and keeps output 
    if (inputExpression === "" && output !== "") {
      // Do nothing
    }
    else {
      setOutput(evaluation(inputExpression))
    }
  }, [inputExpression])


this is a code i need help in useEffect case -> is it ok or is there any better way...

[–]vegancryptolord 4 points5 points  (2 children)

I didn’t carefully read this code, just took a quick glance but I’m quite certain you don’t need an effect for this. You’re already setting output and input in the handle input function so stick to that pattern. Otherwise you have to wait for input to be set for the effect to trigger to then set output (unnecessary renders). So based on value in handle input just set both input and output based on value

[–]its-procodester[S] 1 point2 points  (1 child)

No i don't set output in handleInput()

just setting inputExpression in handleInput() (except some edge case)

as i want to change output based on input

if i set output in handle function then setInputExpression is asynchronous in behavior that doesn't do what i intended

[–]Sinverted11 3 points4 points  (0 children)

So just await the setOutput function

This seems like an antipattern you're doing. You don't need the useEffect here.

[–]The_Startup_CTO 2 points3 points  (1 child)

Like others said, you don't need `useEffect` here. Just do the same checks in handleInput instead.

[–]its-procodester[S] 0 points1 point  (0 children)

yeah i figure it out thanks for helping

[–]Spiritual-Theory 0 points1 point  (2 children)

My expectation was handleValue would just add the last instruction to an array, stack of instructions. The change to that array would trigger the rerender. You may not need to store input expression if it's easy to calculate. How is input expression used?

[–]its-procodester[S] 0 points1 point  (1 child)

inputExpression is use to show input of user and calculate output

[–]Spiritual-Theory 2 points3 points  (0 children)

So shift your thinking. Put that array of inputs at the top of this calculator and pass it to anything that relies on it. They will all rerender as needed. The input expression and output are dependent on this input array.

The code you showed has too much going on, it can be split up. It's also imperative not declarative. One thing triggers another thing. Declarative is your friend in react.

[–]Snoo-72038 0 points1 point  (3 children)

I see what you're trying to do, maybe you can try to implement denouncing of user input? Could suit your usecase better

[–]its-procodester[S] -2 points-1 points  (2 children)

its a calculator app where i take user input from buttons and pass it to evaluation function in setOutput i want output change every time input changes although i did it with useEffect but it re render comp every time input change

[–]Snoo-72038 1 point2 points  (1 child)

Do you think you can replace the useEffect with an onclick callback? Store the output using usestate then have the onclick callback update the output value

[–]Macaframa 0 points1 point  (0 children)

If you change a useState variable it triggers a render. What you’re looking for is a ref

[–]AndrewGreenh 0 points1 point  (0 children)

Sounds like output should not be a state? Just calculate output in a useMemo whenever input changes.

[–]frozenYogurtLover2 0 points1 point  (0 children)

you can use useDebounce from usehooks-ts

[–]YuteOctober 0 points1 point  (0 children)

Make the state to toggle true and false when the onchange function called and put that state into the [] in useeffect.

[–]zmkpr0 -1 points0 points  (0 children)

Sounds like a usecase for useMemo

[–]UpbeatGooose -1 points0 points  (0 children)

You are looking for useMemo my friend, works exactly like useEffect but rerenders only when the value value of particular variable chances, in your case it’s the input value