How to allow only one active useState

I need to create a order logic. I have a array of contacts and i need to ordem them. So i create a modal with 4 options and 4 useStates, i want to create a condition like:

  contactsArr.sort(function (a, b) {
        if(isRecent === true){
          return (a.lastMessage.sentAt > b.lastMessage.sentAt) ? -1 : ((a.lastMessage.sentAt < b.lastMessage.sentAt) ? 1 : 0);
        }
        
        if(isOld === true){
          return (b.lastMessage.sentAt > a.lastMessage.sentAt) ? -1 : ((b.lastMessage.sentAt < a.lastMessage.sentAt) ? 1 : 0);
        }
    ...
}

my orderModal component:

import React, { useState } from 'react';

import { Container, Overlay, Column, Row, Text, Button, Wrapper, Icon } from './styles';

const ModalOrder = ({modalIsOpen, setModalIsOpen}) => {
  
  //change states names
  const [isSelected1, setIsSelected1] = useState(false);
  const [isSelected2, setIsSelected2] = useState(false);
  const [isSelected3, setIsSelected3] = useState(false);
  const [isSelected4, setIsSelected4] = useState(false);
  const [isSelected5, setIsSelected5] = useState(false);

  return (
    <>  
    <Overlay display={modalIsOpen ? "flex" : "none"} onClick={() => setModalIsOpen(s => !s)} >
    </Overlay>
      <Wrapper height={modalIsOpen} shadow="0px -4px 4px rgba(0, 0, 0, 0.1);" display={"flex"} margin="10px 0 0 0" align="center" justify="center" zIndex="2011">
        {/* <Row transform={modalIsOpen ? "translateY(0)" : "translateY(327px)"} cursor="pointer" onClick={() => setModalIsOpen(s => !s)} custom="bottom: 0; position: absolute; margin-bottom: 320px; transition: all ease 0.3s;" width="90px" height="6px" background="#FFF9F9" radius="100px" shadow="0px 4px 4px rgba(0, 0, 0, 0.1);"></Row> */}
        <Icon custom="bottom: 0; position: absolute; margin-bottom: 310px; transition: all ease 0.3s;" transform={modalIsOpen ? "translateY(0)" : "translateY(360px)!important"} onClick={() => setModalIsOpen(s => !s)}/>
        <Column transform={modalIsOpen ? "translateY(0)" : "translateY(309px)"} align="center"  custom="bottom: 0; position: absolute; border-top-left-radius: 35px; border-top-right-radius: 35px; transition: all ease 0.3s;" width="100%" height="308px" background="#FFF" position="absolute">
          <Text margin="16px 0 12px 0" font="bold 16px/21px Segoe UI Regular" color="#448757" >Order</Text>
          
          <Button borderT="1px solid rgb(196, 196, 196, 0.8)" borderB="1px solid rgb(196, 196, 196, 0.8)" onClick={() => setIsSelected1(s => !s)} height="32px" width="100%" align="center" justify="start"> 
            <Row shadow="2px 0px 4px rgba(0, 0, 0, 0.1);" display={isSelected1 ? "flex" : "none"}  custom="border-bottom-right-radius: 5px; border-top-right-radius: 5px; position: absolute; left: 0;" width="10px" height="32px" background="#448757" /> 
            <Text margin="0 0 0 20px" font="normal 14px/19px Segoe UI Regular" color="#525252" >Leatest</Text> 
          </Button>
         
          <Button borderB="1px solid rgb(196, 196, 196, 0.8)" onClick={() => setIsSelected2(s => !s)} height="32px" width="100%" align="center" justify="start">
            <Row shadow="2px 0px 4px rgba(0, 0, 0, 0.1);" display={isSelected2 ? "flex" : "none"}  custom="border-bottom-right-radius: 5px; border-top-right-radius: 5px; position: absolute; left: 0;" width="10px" height="32px" background="#448757" />  
            <Text margin="0 0 0 20px" font="normal 14px/19px Segoe UI Regular" color="#525252" >Oldest</Text> 
          </Button>
         
          <Button borderB="1px solid rgb(196, 196, 196, 0.8)" onClick={() => setIsSelected3(s => !s)} height="32px" width="100%" align="center" justify="start">
            <Row shadow="2px 0px 4px rgba(0, 0, 0, 0.1);" display={isSelected3 ? "flex" : "none"}  custom="border-bottom-right-radius: 5px; border-top-right-radius: 5px; position: absolute; left: 0;" width="10px" height="32px" background="#448757" />  
            <Text margin="0 0 0 20px" font="normal 14px/19px Segoe UI Regular" color="#525252" >Read</Text> 
          </Button>
          
          <Button borderB="1px solid rgb(196, 196, 196, 0.8)" onClick={() => setIsSelected4(s => !s)} height="32px" width="100%" align="center" justify="start"> 
            <Row shadow="2px 0px 4px rgba(0, 0, 0, 0.1);" display={isSelected4 ? "flex" : "none"}  custom="border-bottom-right-radius: 5px; border-top-right-radius: 5px; position: absolute; left: 0;" width="10px" height="32px" background="#448757" /> 
            <Text margin="0 0 0 20px" font="normal 14px/19px Segoe UI Regular" color="#525252" >Unread</Text> 
          </Button>
 
        </Column>
      </Wrapper>
    </>
  );
};

export default ModalOrder;

What can i do to keep only one useState as true? (active) Without having to create 4 different consts that set the chosen one to TRUE and the others to False

My UI

enter image description here

Answer

you can create a CustomButton component first to keep dry your code:

const CustomButton = ({selected, setSelected, children}) => (     
  <Button borderT="1px solid rgb(196, 196, 196, 0.8)" borderB="1px solid rgb(196, 196, 196, 0.8)" onClick={setSelected} height="32px" width="100%" align="center" justify="start"> 
    <Row shadow="2px 0px 4px rgba(0, 0, 0, 0.1);" display={selected ? "flex" : "none"}  custom="border-bottom-right-radius: 5px; border-top-right-radius: 5px; position: absolute; left: 0;" width="10px" height="32px" background="#448757" /> 
    <Text margin="0 0 0 20px" font="normal 14px/19px Segoe UI Regular" color="#525252" >{children}</Text> 
  </Button>
)

then create a state that has initial value null. Create a buttons variable, with its content. For this example you can use the content to set your selected state and compare (since all are unique), but often is better to have an unique key to it.

Then you loop through your buttons where you pass selected and setSelected like below:

const ModalOrder = ({modalIsOpen, setModalIsOpen}) => {
  
  //change states names
  const [selected, setSelected] = useState(null);
  const buttons = ['Leatest', 'Oldest', 'Read', 'Unread'];

  return (
    <>  
    <Overlay display={modalIsOpen ? "flex" : "none"} onClick={() => setModalIsOpen(s => !s)} >
    </Overlay>
      <Wrapper height={modalIsOpen} shadow="0px -4px 4px rgba(0, 0, 0, 0.1);" display={"flex"} margin="10px 0 0 0" align="center" justify="center" zIndex="2011">
        {/* <Row transform={modalIsOpen ? "translateY(0)" : "translateY(327px)"} cursor="pointer" onClick={() => setModalIsOpen(s => !s)} custom="bottom: 0; position: absolute; margin-bottom: 320px; transition: all ease 0.3s;" width="90px" height="6px" background="#FFF9F9" radius="100px" shadow="0px 4px 4px rgba(0, 0, 0, 0.1);"></Row> */}
        <Icon custom="bottom: 0; position: absolute; margin-bottom: 310px; transition: all ease 0.3s;" transform={modalIsOpen ? "translateY(0)" : "translateY(360px)!important"} onClick={() => setModalIsOpen(s => !s)}/>
        <Column transform={modalIsOpen ? "translateY(0)" : "translateY(309px)"} align="center"  custom="bottom: 0; position: absolute; border-top-left-radius: 35px; border-top-right-radius: 35px; transition: all ease 0.3s;" width="100%" height="308px" background="#FFF" position="absolute">
          <Text margin="16px 0 12px 0" font="bold 16px/21px Segoe UI Regular" color="#448757" >Order</Text>
          
          { 
            buttons.map(content => (
              <CustomButton key={content} 
                      selected={selected === content}
                      setSelected={() => setSelected(content)}>{content}
              </CustomButton>
            ))
          }
 
        </Column>
      </Wrapper>
    </>
  );
};

export default ModalOrder;

Leave a Reply

Your email address will not be published. Required fields are marked *