I built a ButtonStepper
component and it's sharing quite a bit of the same logic, so I was wondering if it could be refactored better. It's sharing quite a bit of code with incrementDisabled
and decrementDisabled
because I have to account for the button color changing from black to grey and disabling the TouchableOpacity
when the mix or max is reached.
Also, should I be using useMemo
or useCallback
at all?
// TypeScript Type: Props
interface IProps {
onChange: (value: number) => void;
darkMode?: boolean;
minValue?: number;
maxValue?: number;
stepValue?: number;
}
// Component: Button (Stepper)
const ButtonStepper = ({
onChange,
darkMode = false,
minValue = Number.NEGATIVE_INFINITY,
maxValue = Number.POSITIVE_INFINITY,
stepValue = 1,
}: IProps): JSX.Element => {
// React Hooks: State
const [value, setValue] = useState<number>(0);
// React Hooks: Lifecycle Methods
useEffect(() => {
onChange(value);
}, [onChange, value]);
// Increment Disabled
const incrementDisabled = (): boolean => {
// Disabled
if (maxValue < value + stepValue) {
return true;
}
// Active
else {
return false;
}
};
// Decrement Disabled
const decrementDisabled = (): boolean => {
// Disabled
if (minValue > value - stepValue) {
return true;
}
// Active
else {
return false;
}
};
// On Increment
const onIncrement = (): void => {
// Check Max Value
if (!incrementDisabled()) {
setValue(value + stepValue);
}
};
// On Decrement
const onDecrement = (): void => {
// Check Min Value
if (!decrementDisabled()) {
setValue(value - stepValue);
}
};
// Render Decrement Icon Color
const renderDecrementIconColor = (): '#000000' | '#7D7D7D' => {
// Dark
if (darkMode) {
// Disabled
if (decrementDisabled()) {
return '#7D7D7D';
}
// Active
else {
return '#000000';
}
}
// Light
else {
// Disabled
if (decrementDisabled()) {
return '#7D7D7D';
}
// Active
else {
return '#000000';
}
}
};
// Render Increment Icon Color
const renderIncrementIconColor = (): '#000000' | '#7D7D7D' => {
// Dark
if (darkMode) {
// Disabled
if (incrementDisabled()) {
return '#7D7D7D';
}
// Active
else {
return '#000000';
}
}
// Light
else {
// Disabled
if (incrementDisabled()) {
return '#7D7D7D';
}
// Active
else {
return '#000000';
}
}
};
return (
<View style={darkMode ? styles.containerDark : styles.containerLight}>
<TouchableOpacity
style={darkMode ? styles.iconContainerDark : styles.iconContainerLight}
onPress={onDecrement}
disabled={decrementDisabled()}
accessibilityLabel="Decrement"
accessibilityRole="button"
>
<Icon name="ios-remove" color={renderDecrementIconColor()} size={27} />
</TouchableOpacity>
<View style={darkMode ? styles.dividerDark : styles.dividerLight} />
<TouchableOpacity
style={darkMode ? styles.iconContainerDark : styles.iconContainerLight}
onPress={onIncrement}
disabled={incrementDisabled()}
accessibilityLabel="Increment"
accessibilityRole="button"
>
<Icon name="ios-add-outline" color={renderIncrementIconColor()} size={27} />
</TouchableOpacity>
</View>
);
};
```