简体   繁体   中英

React + Redux: Changing input focus programatically

I have a react application with a 'yes/no' question interface. I'm using redux to manage state.

The app presents a series of input fields, which are added dynamically.

When a question is answered with a 'y' or 'n' keystroke, I want the next input in the series to get focus automatically -- enabling fast data-entry. This is proving surprisingly difficult!

My redux store contains the current question's index - I want this to translate into focus on that input.

/*Input Component*/
const quizQs = ({

    questionArray = ["Q1", "Q2", "Q3", "Q4"]
    currentQIndex, //From Store
    changeQIndex,  //Action

}) => {


    const _handleKeyDown = (e) => {
        if(e.key == 'y' || e.key == 'n'){
          //Dispatches Action that increases current currentQIndex'
        }
    }
    //_handleFocus()... for updating currentQIndex if an input is focused by the user


    return (
        {questionArray.map((q, index) => {

            return(
                <input
                  key={index}
                  onKeyDown={_handleKeyDown}
                  onFocus={_handleFocus}
                  type="text"
                  placeholder={q}
                  />
            )
        })}
        )
}


/*Main Component -- Connected to Store*/
class myQuiz extends React.Component {

constructor(props){
    super(props);
}


render(){
    return(
        <div>

            <quizQs
                currentQIndex = {this.props.currentQIndex} 
                changeQIndex = {this.props.changeQIndex}
                />
        </div>

    )}
}

I have tried setting autoFocus = true , if the store's 'currentQIndex' matches the index of that particular question, in the 'quizQs' component. This method is able to focus the specified field when the page first renders, but the focus does not change when the 'currentQIndex' of the store changes.

As I have searched for an answer, React 'refs' + use of a callback would seem to be the way to go, ( https://reactjs.org/docs/refs-and-the-dom.html#the-ref-callback-attribute ), but I cannot figure out how to set up such 'focus' callback, that responds to changes in the Redux store.

In addition, in order to use Refs , the component must be set up as a class, not an arrow function. AFAIK, it is not good practice to have multiple classes in one file, and it does not seem appropriate to connect so many different components to a redux store.

I'd appreciate help.

Here is simple example of what you are trying to achieve: https://codesandbox.io/s/z64qw3nkzx

I simplified it a bit, but the point is there.

As .focus() is native method on the DOM element, you need a way of tracking those input elements. For that in React there is ref prop. It accepts a function with has one parameter which is the actual DOM element of the component.

You'll see that I put all of the DOM references into an array:

<input
  ref={el => this.questionInputElements[index] = el}
  key={index}
  // all other props
/>

and on key up* find the next element in the array and focus it:

const nextInput = this.questionInputElements[index + 1];

if (nextInput) {
  nextInput.focus();
}

* it needs to be on key up (rather than key down) as it would focus the next field before and print y/n in the next input. Try it for fun :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM