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

\$\endgroup\$
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).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.