2
\$\begingroup\$

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?

enter image description here

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jun 21, 2019 at 14:19
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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:

  1. Save the refs in an array in one instance variable
  2. Store the current values in an array in one state field
  3. 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).

answered Sep 3, 2019 at 20:42
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.