Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Focus input after redux dispatch finished

I am dynamically creating list of inputs with React and Redux. After clicking a button an input is added to the end of list. I need to focus last added input. I tried this code but it focuses penultimate input

const mapDispatchToProps = (dispatch, ownProps) => ({
    onOptionsChange: (newOptions) => {
        dispatch(formActions.updateOptions(newOptions));
    }
});

...
this.props.onOptionsChange({ ...this.props, inputsList}); // change list of inputs
ReactDOM.findDOMNode(this.inputs[this.props.choices.length - 1]).focus();

In logs I can see that focus() is executed before props from state are updated. How can I wait for dispatch to finish?

like image 833
igo Avatar asked Dec 28 '16 16:12

igo


2 Answers

Promisify your dispatch

Lets write a middleware that returns a promise after completing the dispatch.

const thenMiddleware = store => next => action => {
    return new Promise((resolve, reject) => {
        try {
            resolve(next(action));
        } catch(e) {
            reject(e);
        }
    })
};

Prepare your store first, by installing the middleware

import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers/index';

/**
 * Our star of the show
 */
const thenMiddleware = store => next => action => {
    return new Promise((resolve, reject) => {
        try {
            resolve(next(action));
        } catch(e) {
            reject(e);
        }
    })
};

const store = createStore(
  rootReducer,
  applyMiddleware(thenMiddleware)
);

Now we have to return the dispatch inside our mapDispatchToProps method

const mapDispatchToProps = (dispatch, ownProps) => ({
  onOptionsChange: (newOptions) => {
    return dispatch(formActions.updateOptions(newOptions));
  }
});

Finally hook your event on complete

Now that you know which input you created last time, you can attach an on complete function to this dispatch.

this.props.onOptionsChange(newOptions).then(() => {
  // do your input focusing here
});
like image 55
FlatLander Avatar answered Nov 02 '22 08:11

FlatLander


I would implement componentDidUpdate and check the length of your "input-array" or whatever data-structure you are using:

componentDidUpdate(prevProps, prevState) {
   if (prevProps.choices.length < this.props.choices.length) {
      ReactDOM.findDOMNode(this.inputs[this.props.choices.length - 1]).focus();
   }
}
like image 2
Hulvej Avatar answered Nov 02 '22 09:11

Hulvej