Ввод фокуса после отправки скидки

Я динамически создаю список входов с React и Redux. После нажатия кнопки ввод добавляется в конец списка. Мне нужно сфокусировать последний добавленный ввод. Я пробовал этот код, но он фокусирует предпоследний вход

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();

В журналах я вижу, что focus() выполняется до обновления реквизита из состояния. Как подождать окончания отправки?

Ответы

Ответ 1

Я бы выполнил componentDidUpdate и проверил длину вашего "входного массива" или любой другой структуры данных, которую вы используете:

componentDidUpdate(prevProps, prevState) {
   if (prevProps.choices.length < this.props.choices.length) {
      ReactDOM.findDOMNode(this.inputs[this.props.choices.length - 1]).focus();
   }
}

Ответ 2

Продвигайте свою рассылку

Позволяет написать промежуточное программное обеспечение, которое возвращает обещание после завершения отправки.

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

Сначала подготовьте свой магазин, установив промежуточное ПО

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)
);

Теперь нам нужно вернуть отправку внутри нашего метода mapDispatchToProps

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

Наконец, завершите свое мероприятие полным

Теперь, когда вы знаете, какой вход вы создали в последний раз, вы можете прикрепить к этой отправке полную функцию.

this.props.onOptionsChange(newOptions).then(() => {
  // do your input focusing here
});

Ответ 3

Создайте новый компонент упаковки для элемента input. Этот компонент будет автофокусироваться при визуализации.

class Input extends React.Component {
    keepRef = (ref) => {
        this.ref = ref;
    }

    componentDidMount() {
        this.ref.focus();
    }

    render () {
        return (
            <input ref={this.keepRef} {...this.props} />
        )
    }
}

Если вы не хотите, чтобы компонент input обрабатывал фокус, переместите логику в его родительский.

Ответ 4

Я столкнулся с аналогичной проблемой, в которой у меня был список элементов, и мне нужно сосредоточиться на последнем элементе всякий раз, когда добавляется новый элемент. В приведенном ниже коде используется флюсовая архитектура, но я думаю, он должен решить вашу проблему.

addNewItem: function() {
    var self = this;
    var list = this.state.list || {};
    var listOrder = this.state.listOrder || [];
    var newKey = "some_random_key";

    list[newKey] = {
        "product": ""
    };
    listOrder.push(newKey);
    this.state.list = list;
    this.state.listOrder = listOrder;
    this.setState({list: this.state.list, listOrder: this.state.listOrder, showSaveButton: true});
    setTimeout(function(){
        $(".buy-form-item-list-row .buy-form-item-list-item-name").last().focus();
    }, 0);
},

Итак, в приведенном выше коде.. listOrder содержит ключи списка элементов. Например: list - это объект, который содержит элемент. Например:

listOrder = [ran_1, ran_2];

список = { ran_1: {   продукт: "Яйца - 5" }, ran_2: {   продукт: "Хлеб - 1" } }

метод рендеринга, перебираем listOrder и создаем тег ввода с классомName = "buy-form-item-list-item-name" для каждого элемента.

Трюк для фокусировки на последнем элементе - это setTimeout с интервалом 0. Когда вы вызываете setState, он не запускает функцию рендеринга в тот момент сам, вместо этого он ожидает, что функция будет выполнена полностью.

Надеюсь, это поможет.