How to refactor this lengthy if/else

Viewed 128

I wrote this if/else which works fine, but it's pretty long. I'd be really interested in seeing which methods other developers would use to shorten it.

At the moment I think it looks very much like a beginner wrote it (which is correct). I'd love to see how others would approach it.

I should mention that I'm working in React Native.

getBatteryIcon() {
    if (this.props.batteryLevel >= 81 && this.props.batteryLevel <= 100) {
      return (
        <Image
          source={require('./../../../android/app/src/main/res/drawable/batterylevel_four.png')}
        />
      )
    } else if (this.props.batteryLevel >= 51 && this.props.batteryLevel <= 80) {
      return (
        <Image
          source={require('./../../../android/app/src/main/res/drawable/batterylevel_three.png')}
        />
      )
    } else if (this.props.batteryLevel >= 25 && this.props.batteryLevel <= 50) {
      return (
        <Image
          source={require('./../../../android/app/src/main/res/drawable/batterylevel_two.png')}
        />
      )
    } else {
      return (
        <Image
          source={require('./../../../android/app/src/main/res/drawable/batterylevel_one.png')}
        />
      )
    }
  }
2 Answers

Since you're using if/else if (well, also because you're returning in each if's block), you can leave off half of those conditions, because you know they won't be true:

if (this.props.batteryLevel >= 81) { // I assume it can't go past 100
  return (
    <Image
      source={require('./../../../android/app/src/main/res/drawable/batterylevel_four.png')}
    />
  )
} else if (this.props.batteryLevel >= 51) { // Thanks to the `else`, you know it's not 81 or higher
  return (
    <Image
      source={require('./../../../android/app/src/main/res/drawable/batterylevel_three.png')}
    />
  )
} else if (this.props.batteryLevel >= 25) { // You know it's not 51 or higher
  return (
    <Image
      source={require('./../../../android/app/src/main/res/drawable/batterylevel_two.png')}
    />
  )
} else {
  return (
    <Image
      source={require('./../../../android/app/src/main/res/drawable/batterylevel_one.png')}
    />
  )
}

Another option is to have a list of thresholds you loop through. Apparently, React Native doesn't let you have variables in require (thank you Matt Aft and OsDev), so we can't remove as much of the duplication as we might like, but:

const batteryLevels = [
    {level: 81, source: require("./../../../android/app/src/main/res/drawable/batterylevel_four")},
    {level: 51, source: require("./../../../android/app/src/main/res/drawable/batterylevel_three")},
    {level: 25, source: require("./../../../android/app/src/main/res/drawable/batterylevel_two")},
    {level: 0,  source: require("./../../../android/app/src/main/res/drawable/batterylevel_one")}
//          ^---- or possibly `-Infinity`, see note below
];

then it's

let {source} = batteryLevels.find(({level}) => this.props.batteryLevel >= level);
return (
  <Image
    source={source}
  />
);

Note that that assumes this.props.batteryLevel will always be >= 0. You could make the last one level: -Infinity instead of level: 0 instead, to be really sure. :-)


For the general case, but this won't work for React Native because of the require restriction, we could factor out the path and most of the filename:

// NOT ON REACT NATIVE

let level;
if (this.props.batteryLevel >= 81) { // I assume it can't go past 100
  level = "four";
} else if (this.props.batteryLevel >= 51) { // You know it's not 81 or higher
  level = "three";
} else if (this.props.batteryLevel >= 25) { // You know it's not 51 or higher
  level = "two";
} else {
  level = "one";
}
return (
  <Image
    source={require(`./../../../android/app/src/main/res/drawable/batterylevel_${level}.png`)}
  />
);
    let level;
var getBatteryIcon = function (batteryLevel) {
    const x = batteryLevel;
    switch (true) {
        case (x > 80):
            level = '/batterylevel_four.png';
            break;
        case (x > 50):
            level = '/batterylevel_three.png';
            break;
        case (x > 24):
            level = '/batterylevel_two.png';
            break;
        default:
            level = 'batterylevel_one.png';
            break;
    }

    return './../../../android/app/src/main/res/drawable' + level;
}

console.log(getBatteryIcon(55));
Related