I have created a date component (working GIF at the bottom; please ignore the styling).
There isn't a problem with the working of the code but rather the code I wrote seems messy and something hard for any other person to comprehend.
This is what I am doing: For the date Component in screen, I am creating refs and state like this
class OnBoarding extends PureComponent {
constructor(props) {
super(props)
this.d1 = React.createRef()
this.d2 = React.createRef()
this.d3 = React.createRef()
this.d4 = React.createRef()
this.d5 = React.createRef()
this.d6 = React.createRef()
this.d7 = React.createRef()
this.d8 = React.createRef()
}
state = {
name: '',
emailAddress: '',
dob: '',
male: null,
female: null,
keyboard: false,
d1: null,
d2: null,
d3: null,
d4: null,
d5: null,
d6: null,
d7: null,
d8: null
}
dobHandler(number, flag) {
const completeFlag = `d${flag}`
this.setState({[completeFlag]: number})
flag = flag + 1
if (flag < 9 && number) {
const nextFlag = `d${flag}`
const textInputToFocus = this[nextFlag]
textInputToFocus.current.focus()
}
}
And then rendering them like this
<View style={styles.dob}>
<TextInput
ref={this.d1}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="D"
onChangeText={number => this.dobHandler(number, 1)}
/>
<TextInput
ref={this.d2}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="D"
onChangeText={number => this.dobHandler(number, 2)}
/>
<Text>/</Text>
<TextInput
ref={this.d3}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="M"
onChangeText={number => this.dobHandler(number, 3)}
/>
<TextInput
ref={this.d4}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="M"
onChangeText={number => this.dobHandler(number, 4)}
/>
<Text>/</Text>
<TextInput
ref={this.d5}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="Y"
onChangeText={number => this.dobHandler(number, 5)}
/>
<TextInput
ref={this.d6}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="Y"
onChangeText={number => this.dobHandler(number, 6)}
/>
<TextInput
ref={this.d7}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="Y"
onChangeText={number => this.dobHandler(number, 7)}
/>
<TextInput
ref={this.d8}
numberOfLines={1}
maxLength={1}
style={styles.textInputDob}
keyboardType="numeric"
placeholder="Y"
onChangeText={number => this.dobHandler(number, 8)}
/>
</View>
The reason I have made so many ref
is because the moment someone enters something in the current textInput
, I want the focus to moved to the next one, which happens in dobHandler
function.
Can someone help me in improving quality/optimizing and if this is the wrong way of doing it, then hint me on how to achieve this alternatively?
1 Answer 1
You're doing it correct – this is a perfect use case for refs and the state management is done equally well. However, your code suffers from repetition and can be DRYed up. A quick way to greatly reduce the amount of code and resulting complexity is to simply use arrays:
- Save the refs in an array in one instance variable
- Store the current values in an array in one state field
- Render the text fields inside an iterator over one of them
A version of this, adjusted to the web / ReactDOM, might look like this:
class OnBoarding extends React.Component {
state = {
dateFieldValues: [null, null, null, null, null, null, null, null]
}
constructor(props) {
super(props)
this.dateFieldRefs = this.state.dateFieldValues.map(() => React.createRef())
}
setDateFieldValue(index, text) {
this.setState(({dateFieldValues}) => {
dateFieldValues[index] = text
return {dateFieldValues}
})
if (index < this.state.dateFieldValues.length - 1) {
this.dateFieldRefs[index + 1].current.focus()
}
}
render() {
return this.dateFieldRefs.map((ref, index) => (
<input
ref={ref}
onChange={text => this.setDateFieldValue(index, text)}
/>
))
}
}
ReactDOM.render(<OnBoarding />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
A library such as lodash could be used to make the array initialization more readable, i.e. range(8).map(() => null)
.
Explore related questions
See similar questions with these tags.