2016-12-28 16 views
15

我使用React和Redux動態創建輸入列表。點擊一個按鈕後,輸入被添加到列表的末尾。我需要關注最後添加的輸入。我想這個代碼,但它着重倒數第二個輸入REDX發送完成後的焦點輸入

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 **渲染中不會被調用! – 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

我遇到了類似的問題,其中,我有項目清單和每當添加新項目時,我都需要關注最後一個元素。下面的代碼是使用flux架構,但我想它應該可以解決您的問題。

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包含的項目列表的鑰匙。例如: 列表是包含該項目的對象。例如:

listOrder = [ran_1,ran_2];

列表= { ran_1:{ 產品: 「雞蛋 - 5」 }, ran_2:{ 產品: 「麪包 - 1」 } }

渲染方法,迭代listOrder和爲每個項目創建一個帶有className =「buy-form-item-list-item-name」的Input標籤。

關注最後一項的技巧是setTimeout,間隔爲0.當您調用setState時,它本身不會觸發渲染函數,而是等待函數完全執行。

希望這會有所幫助。

+0

Redux!== flux。使用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