Home > Software engineering >  How would I toggle object properties to false, whenever one of the properties is set to true in Reac
How would I toggle object properties to false, whenever one of the properties is set to true in Reac

Time:09-20

The Problem:

  • I am tasked at work to create 3 buttons that are programmed with separate filters that ultimately displays different tickets in the tickets table.
  • All the functionality is done, and it displays the filtered tickets.
  • HOWEVER, I have one issue that would complete the task and allow me to do a PR.
  • Right now, I am using an object inside of a useState hook.
  • The object has 3 properties, one for each button, and their initial state is set to false.
  • Whenever a button is clicked via an onClick updateButtonObjStateHandler function, the function SHOULD set that buttons corresponding property to true, and if one of the other properties is already true, it should be set to false.
  • So basically only one of the 3 properties should be set to true at any given time, and whenever another button is clicked, that property is now toggled to true, and the others are toggled to false.
  • We are very loosely using typescript, and there is an interface on the obj. But it can removed if the solution requires it. I would like to keep it though.

Code Examples

The button object: when button is clicked, toggle its related property to true. whenever new button is clicked. set the property related to that newly clicked button to true. and set all others to false.

// The initial state has all of the properties set to false.
  const [exampleObj, setExampleObj] = useState<IExampleObj>({
    isCanceledBtn: false,
    isExpiredBtn: false,
    isSubmittedBtn: false
  })

The button object interface That is being imported from another file

export interface IExampleObj {
    isCanceledBtn: boolean,
    isExpiredBtn: boolean,
    isSubmittedBtn: boolean
}

Expected Outcome

    isCanceledBtn: false,
    isExpiredBtn: true,
    isSubmittedBtn: false

    isCanceledBtn: true,
    isExpiredBtn: false,
    isSubmittedBtn: false

    isCanceledBtn: false,
    isExpiredBtn: false,
    isSubmittedBtn: true

What I have tried:

// Inside of the onClick function handler
// I have tried updating the object property for the button that is clicked
// Here is some psuedocode
   if 'canceled' ->   
        setExampleObj((prevVal: IKpiUpdaterObj) => ({
        ...prevVal,
        isCanceledBtn: true
      }))
   if 'closed' ->   
        setExampleObj((prevVal: IKpiUpdaterObj) => ({
        ...prevVal,
        isExpiredBtn: true
      }))
   if 'submitted' ->   
        setExampleObj((prevVal: IKpiUpdaterObj) => ({
        ...prevVal,
        isSubmittedBtn: true
      }))
// This code is bad, when I click the button, it updates the related state to true, and it displays those filtered tickets
// When another button is clicked, it sets the state to true, and displays those filtered tickets.
// and the same is true for the third button.
//But then that's it, when I click the buttons furthermore, there is no action because all the buttons are now toggled to true and are never reset to false when another button is clicked

MY ULTIMATE GOAL:

to create a function that can toggle object properties from true to false based on which btn is clicked....WITHOUT having to manually write out the object values for each button.

I want to have this.

one object with functionality to toggle from true to false based on the button that was clicked.

    // values toggle true or false based on which button is clicked button
    // only one can be true, or all can be false
    isCanceledBtn: false,
    isExpiredBtn: true,
    isSubmittedBtn: false

I am trying to avoid this

manually setting the object values for each button

    // Button 1
    isCanceledBtn: false,
    isExpiredBtn: true,
    isSubmittedBtn: false
    
    // Button 2
    isCanceledBtn: true,
    isExpiredBtn: false,
    isSubmittedBtn: false

    // button 3
    isCanceledBtn: false,
    isExpiredBtn: false,
    isSubmittedBtn: true

CodePudding user response:

This should be as straightforward as simply setting the new state, not to one based on the old state but with one property toggled, but to the object with the values you know it will need to have: the one property true, and the others false.

So in your pseudocode version, this:

   if 'canceled' ->   
        setExampleObj((prevVal: IKpiUpdaterObj) => ({
        ...prevVal,
        isCanceledBtn: true
      }))

needs to become:

   if 'canceled' ->   
        setExampleObj({
        isCanceledBtn: true,
        isExpiredBtn: false,
        isSubmittedBtn: false
      })

and the same of course for the other 2 cases.

However, this approach is a little awkward, and I would encourage you to use a more descriptive type. Since you can only ever have one button with a "true" value, the type should be something like:

type ButtonSelected = "canceled" | "expired" | "submitted";

(possibly with an option for none being selected - it isn't clear to me if that's a valid case or not). One of the advantages of using types is to have them describe what the possible values are in your code - making invalid states literally unrepresentable is something you should always strive for to make your code better represent your business logic.

  • Related