what is the best way to implement conditional props, i having something like this, a component that would be a view or a button that base on a props, which i call here CountdownButtonI
It look like this
class CountDownButton extends Component<CountdownButtonI> {
constructor(props:CountdownButtonI) {
super(props);
}
render() {
const { t, title, onPress, time } = this.props;
return time ? (
<View style={{ ...Layout.flexView }}>
<Label text={t('common.countdown.otpCountdown')} style={{ ...LabelStyle.SubBodyText, color: Colors.black }} />
<Label
text={moment.utc(time * 1000).format('HH:mm:ss')}
style={{ ...LabelStyle.SubBodyTextMedium, fontWeight: '500', color: Colors.black }}
/>
</View>
) : (
<TouchableOpacity activeOpacity={1} style={styles.buttonContainer} onPress={onPress}>
<Label text={title} style={{ ...LabelStyle.BodyTextMedium, color: Colors.white }} />
</TouchableOpacity>
);
}
}
For CountdownButtonI i set like this
interface CountdownButtonI{
t: any;
title: any;
time: any;
}
But i feel it not optimal at all, like, when i have time
props, onPress
still visible, how can i avoid this, like, if i have time
props, the onPress
will raise an error
CodePudding user response:
Consider using discriminated unions.
import React from 'react'
interface WithTime {
withTime: true
t: (val: string) => string;
time: number;
}
interface WithTitle {
withTime: false
title: string;
onPress: () => void
}
type Props = WithTime | WithTitle
const render = (props: Props) => {
const { withTime } = props;
if (withTime) {
const { t, time } = props;
return (
<div>
<p>{time}</p>
<p>{t('hello')}</p>
</div>
)
}
const { title, onPress } = props;
return (
<div>
<p>{title}</p>
<button onClick={onPress}>click</button>
</div>
)
}
withTime
property is a discriminator. It exists in each union and has different values.
CodePudding user response:
@captain-yossarian has given you a good answer to the question that you are asking, but IMO you are asking the wrong questions.
There is no reason that your two situations (the view and the button) should be the same component. They do not share any props, any logic, any UI, or even any styles.
You are adding a level of complexity that simply does not need to be there.
Do yourself a favor and make this into two separate components. Each component will only accept the props which make sense for that specific case.
interface CountDownButtonProps {
onPress: () => void; // or (event: GestureResponderEvent) => void
title: string;
}
export const CountDownButton = ({ onPress, title }: CountDownButtonProps) => {
return (
<TouchableOpacity activeOpacity={1} style={styles.buttonContainer} onPress={onPress}>
<Label text={title} style={{ ...LabelStyle.BodyTextMedium, color: Colors.white }} />
</TouchableOpacity>
);
}
interface CountDownTimerProps {
time: number;
}
export const CountDownTimer = ({ time }: CountDownTimerProps) => {
const { t } = useTranslation();
return (
<View style={{ ...Layout.flexView }}>
<Label
text={t('common.countdown.otpCountdown')}
style={{ ...LabelStyle.SubBodyText, color: Colors.black }}
/>
<Label
text={moment.utc(time * 1000).format('HH:mm:ss')}
style={{ ...LabelStyle.SubBodyTextMedium, fontWeight: '500', color: Colors.black }}
/>
</View>
);
}