2016-12-28 2 views
15

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

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

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

+0

Вы можете добавить опцию 'autoFocus' для ввода? – BravoZulu

+0

autoFocus выглядит как интересный выбор – FlatLander

ответ

0

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

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

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

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

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

+0

Или используйте 'componentWillReceiveProps (nextProps)' и выполняйте проверку '! ==' и затем фокусируйтесь. –

+0

'componentWillReceiveProps' не вызывается в ** first ** render! – Andreyco

+0

Почему бы и нет? : D – martinarroyo

2

Я бы реализовать componentDidUpdate и проверить длину вашего «входного массив» или что-то структуры данных вы используете:

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

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

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, он не вызывает функцию рендеринга в тот момент сам, вместо этого он ждет выполнения функции полностью.

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

+0

Redux! == поток. Использование setTimeout - это взлом, а не хорошее решение. –

2

Promisify ваша диспетчерская

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

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 
}); 
+0

Вам не нужно подключать его через «mapDispatchToProps», и вы не можете просто «затем» получить результат. Его оригинальный удар должен вернуть «Обещание» для этого. –

+0

хорошая точка, исправление – FlatLander

+0

@ Derk-Jan Я написал специальное промежуточное программное обеспечение, чтобы это произошло. Хорошо ли это сейчас? – FlatLander

Смежные вопросы