'Conditionally rendering content in react

I am having a functional component that takes two items as props. The values of each properties could be undefined, "", null, "null", or a valid string (for example, "test").

I need to conditionally render these props based on values

if prop1 and prop2 are both present then it should display as prop1(prop2), if either one of them are present then it should either be prop1 or just prop2. In case both of them are not present then should display "Not Available". Only valid strings should be taken. If values has either undefined, "", null, "null" it should not be displayed.

I am having trouble building up the logic. This is what I have tried.

const Test = (props) => {
   let { prop1, prop2 } = props;
    let content: string;
    if ((!prop1 || prop1 === "null") && (!prop2 || prop2 === "null")) {
        content = "Not Available";
    } else if (!!prop1 && !!prop2) {
        content = `${prop1} (${prop2})`;
    } else {
       content = `${prop1 || prop2}`;
    }
   
  return (
    <>
      {content}
    </>
  );

}


Solution 1:[1]

I guess this is a tricky condition by itself, so I wouldn't worry too much if it looks a bit weird. One think you can do tho is to organize the component code in variables and smaller functions like so:

const isDefined = (value) => value !== "null" && !!value
const buildString = (prop1, prop2) => {
  let string = prop1 || prop2
  return prop1 && prop2
    ? `${string} (${prop2})`
    : string
}

const Test = ({ prop1, prop2 }) => {
  const someDefined = isDefined(prop1) || isDefined(prop2);
   
  return (
    <>
      {!someAreDefined && "Not Available"}
      {someAreDefined && buildString(prop1, prop2)}
    </>
  );
}

I think that helps a lot with readability and understanding the flow and possible outputs for this component.

Solution 2:[2]

How about a separate function that returns whether or not the value is valid?

function propIsValid(value) {
  // valid if truthy and not "null" (string)
  return !!prop && value != "null";
}

The above checks for a thuthy value, which means that all falsy values are considered invalid. This includes null, undefined and "", but also false, NaN and 0. Which might or might not be a problem, depending on your context.

If you want a more target approach you could use the following:

const invalid = [undefined, null, "", "null"];
return !invalid.includes(value);

Then simplify your component to:

const Test = ({ prop1, prop2 }) => {
  const allValid   = [prop1, prop2].every(propIsValid);
  const firstValid = [prop1, prop2].find(propIsValid);

  if (allValid) {
    return <>{prop1}({prop2})</>;
  } else if (firstValid) {
    return <>{firstValid}</>;
  } else {
    return <>Not Available</>;
  }
}

This uses every() to check if both are valid, but this could also be written as propIsValid(prop1) && propIsValid(prop2). find() is used to find the first valid value (if any), this does assume that a valid value is always thuthy.

Solution 3:[3]

Just use a ternary

(prop1 && !/null/.test(prop1)) && (prop2 && !/null/.test(prop2)) ? `${prop1}(${prop2})` : prop1 && !/null/.test(prop1) ? `${prop1}` : prop2 && !/null/.test(prop2) ? `${prop2}` : 'Not Available';

Since undefined "" and null are falsey in nature it will only use regex to test for the pattern null if it needs to. If there are any other values that you want to be considered invalid, just add them to the regex.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ntocampos
Solution 2
Solution 3