Michael Rýdl
Michael Rýdl

Reputation: 97

How Can I Simplify This JSX Conditional Code?

I´ve got this code snippet:

export const MessageWindow: FunctionComponent<MessageWindowProps> = ({ children, buttonsType }) => {

    return (
        <div className={classNames()}>
            <div className={messageWindowContent}>
                {children}
            </div>
            <div className={messageWindowButtons}>
                {buttonsType === "yesno" ?
                    <>
                        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="No" title="No" />
                        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Yes" title="Yes" />
                    </> : buttonsType === "saveclose" ?
                    <>
                        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />
                        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Save" title="Save" />
                    </> : buttonsType === "close" ? 
                    <>
                        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />
                    </> : null
                }
            </div>
        </div>
    );
}

where "buttonsType" is those enums:

export enum ButtonsType {
    yesno = "yesno",
    saveclose = "saveclose",
    close = "close"
}

I´d like to know some better way, to simplify the conditional statement. Or is it possible to have it like this?

Thank you.

Upvotes: 0

Views: 101

Answers (6)

ericgio
ericgio

Reputation: 3519

I think Ray Hatfield's answer is the cleanest solution and avoids repetitive JSX, but I'll add a switch example as an option. Ternary generally seems like a poor option for this case.

let buttons;
switch (buttonsType) {
  case 'yesno':
    buttons =
      <>
        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="No" title="No" />
        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Yes" title="Yes" />
      </>;
    break;
  case 'saveclose':
    buttons =
      <>
        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />
        <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Save" title="Save" />
      </>;
    break;
  case 'close':
    buttons =
      <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />;
    break;
  default:
    buttons = null;
}

return (
  <div className={classNames()}>
    <div className={messageWindowContent}>
      {children}
    </div>
    <div className={messageWindowButtons}>
      {buttons}
    </div>
  </div>
);

Upvotes: 0

ray
ray

Reputation: 27285

You could create a mapping of types to button configuration objects:

const buttons = {
  yesno: [
    { title: 'No', action: () => { /* do stuff */} },
    { title: 'Yes', action: () => { /* do stuff */} },
  ],
  saveclose: [
    { title: 'Save', action: () => { } },
    { title: 'Close', action: () => { } },
  ],
  // etc.
}

And then render buttons according to the configs for the associated type:

buttons[buttonsType].map(({title, action}) => (
  <Button
    key={title}
    color={TextColor.colorPrimary}
    text={title}
    title={title}
    onClick={action}
  />
));

You could make this its own component and just pass in the types prop:

<MessageWindowButtons buttonTypes={buttonTypes} />

Upvotes: 1

Nathan Chappell
Nathan Chappell

Reputation: 2446

I would factor the button into a different component.

export const TheButton = ({ buttonText, callback }) => {                              
  return <TextButton text={buttonText} title={buttonText} onClick={callback} />;      
};                                                                                    
                                                                                      
export const TheButtons = ({ buttonsType }) => {                                      
  const foo = () => {                                                                 
    /*whatever*/                                                                      
  };                                                                                  
  switch (buttonsType) {                                                              
    case "yesno":                                                                     
      return (                                                                        
        <>                                                                            
          <TextButton buttonText="yes" callback={foo} />                              
          <TextButton buttonText="no" callback={foo} />                               
        </>                                                                           
      );                                                                              
    case "saveclose":                                                                 
      return (                                                                        
        <>                                                                            
          <TextButton buttonText="save" callback={foo} />                             
          <TextButton buttonText="close" callback={foo} />                            
        </>                                                                           
      );                                                                              
    case "close":                                                                     
      return (                                                                        
        <>                                                                            
          <TextButton buttonText="close" callback={foo} />                            
        </>                                                                           
      );                                                                              
    default:                                                                          
      return null;                                                                    
  }                                                                                   
};                                                                                    
                                                                                      
export const MessageWindow: FunctionComponent<MessageWindowProps> = ({                
  children,                                                                           
  buttonsType,                                                                        
}) => {                                                                               
  return (                                                                            
    <div className={classNames()}>                                                    
      {" "}                                                                           
      <div className={messageWindowContent}> {children} </div>{" "}            
             <div className={messageWindowButtons}>                        
        {" "}                                                       
        <TheButtons buttonsType={buttonsType} />                    
      </div>{" "}                                                   
    </div>                                                          
  );                                                                
};                                                                  

Upvotes: 0

Shubham Srivastava
Shubham Srivastava

Reputation: 1887

{(buttonsType === "yesno" &&
    <SomeContent/>)
|| (buttonsType === "saveclose" &&
    <SomeOtherContent />)
|| (buttonsType  === "close" &&
    <YetSomeOtherContent />)
||
    <SomeDefaultContent />
}

You can try this; This is almost switch like but in jsx render function directly

Upvotes: 0

Sudhanshu Kumar
Sudhanshu Kumar

Reputation: 2044

<div className={classNames()}>
  <div className={messageWindowContent}>
    {children}
  </div>
  <div className={messageWindowButtons}>
    {{
      yesno: 
      (
        <>
          <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="No" title="No" />
          <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Yes" title="Yes" />
        </>
      ),
      saveclose:
      (
        <>
          <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />
          <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Save" title="Save" />
        </>
      ),
      close:
      (
        <>
          <TextButton color={TextColor.colorPrimary} onClick={function foo() { }} text="Close" title="Close" />
        </>
      ),
    }[buttonType]}
  </div>
</div>

This should work, nesting ternary is fine but affects readability.

Upvotes: 0

maya_nk99
maya_nk99

Reputation: 502

What you can do is separate the jsx for each condition like this:-

  {ButtonsType === "yesno" && (<div>( your html )</div>)}
  {ButtonsType === "saveclose" && (<div>( your html )</div>)}

Upvotes: 0

Related Questions