2017-01-24 15 views
4

我有一個ReactJS組件,裏面有一個HTML <textarea>ReactJS組件中的HTML textarea無法以編程方式選擇沒有setTimeout?

<textarea>value屬性預先填充(見下面...我生成一個鏈接供用戶複製)。

我想自動選擇<textarea>的內容,以便用戶更方便地複製文本。我正在嘗試在React componentDidMount調用中執行此操作。它的工作原理...

據我所知,組件的安裝速度非常緩慢,即使已經調用了componentDidMount,該過程仍在進行中。我這樣說的原因是:如果我直接在componentDidMount之內撥打myTextarea.select(),那麼失敗了 100%的時間。但是,如果我將.select()放在setTimeout(...)調用中,所以在嘗試選擇內容之前等待一會兒,它會在100%的時間內工作工作

編輯/注意:稍微多了一點點後,我發現一些情緒表明使用setTimeout(...)這個目的是不好的做法,所以現在我更加渴望避免使用它。

我可能會缺少什麼,有沒有更好的方法來實現這一目標?

這是我的。

該版本失敗。

var GenerateLinkUi = React.createClass({ 
    componentDidMount: function() { 
    document.getElementById('cyoag-generated-link-textarea').select(); 
    }, 
    render: function() { 
    return (
     <div id='cyoag-generate-link-ui'> 
     <textarea readOnly id='cyoag-generated-link-textarea' value={config.hostDomain + 'link?id=' + this.props.nodeUid} /> 
     </div> 
    ); 
    } 
}); 

這個版本成功。

var GenerateLinkUi = React.createClass({ 
    componentDidMount: function() { 
    setTimeout(function(){ 
     document.getElementById('cyoag-generated-link-textarea').select(); 
    }, 500); 
    }, 
    render: function() { 
    return (
     <div id='cyoag-generate-link-ui'> 
     <textarea readOnly id='cyoag-generated-link-textarea' value={config.hostDomain + 'link?id=' + this.props.nodeUid} /> 
     </div> 
    ); 
    } 
}); 

編輯:這被標記爲重複。相關問題對我提出了更多問題,並沒有提供明確的答案,正如下面的評論所討論的。如果ref在組件安裝後執行,並且componentDidMount也執行「之後」組件安裝,我很難理解這兩者之間的差異,除了ref作爲arg傳遞DOM元素之外,在componentDidMount我不得不使用document.getElementById什麼的。如果有人能夠描述兩者之間的深層差異,我會很感激。

與此同時,我發現了這個問題的其他解決方法,但我仍然渴望瞭解更多關於這個問題。

+0

可能重複[React set render on render after render](http://stackoverflow.com/questions/28889826/react-set-focus-on-input-after-render) – zurfyx

回答

1

我會猜測發生了什麼。

組件是否在componentDidMount之後再次呈現?我想它會再次渲染textarea並覆蓋select(),因爲你已經在實際的DOM上完成了它,而不是虛擬的。

它在使用setTimeout時有效,因爲您在componentDidMount之後發生的所有渲染之後執行此操作。我想如果你再次更新道具,它會再次覆蓋select()

使用refs來解決這個問題。

var GenerateLinkUi = React.createClass({ 
    componentDidMount: function() { 
    this.textArea.select(); 
    }, 
    setTextArea: function(ref) { 
    this.textArea = ref; 
    } 
    render: function() { 
    return (
     <div id='cyoag-generate-link-ui'> 
     <textarea ref={this.setTextArea} readOnly id='cyoag-generated-link-textarea' value={config.hostDomain + 'link?id=' + this.props.nodeUid} /> 
     </div> 
    ); 
    } 
}); 
+0

我在此期間找到了解決方法;但我試圖理解這個答案,因爲看起來是在正確的軌道上。如果後面的渲染被觸發,我找不到是什麼原因造成的。我想這是可能的。我的問題是,如果'ref'在組件掛載後執行,並且'componentDidMount'也在組件掛載後執行,我很難理解這兩者之間的區別,除了'ref'作爲一個DOM元素傳遞ARG;在'componentDidMount'中,我必須使用'document.getElementById'或其他東西。 – Steverino

+1

@Steverino使用'ref'和'document.getElementById'的區別在於React可以看到你對'ref'所做的修改,因爲它修改了渲染的虛擬DOM。 React無法看到您在實際DOM上所做的更改,因此它會使用其上沒有'select()'的虛擬DOM覆蓋它。 記住你渲染的'