2016-03-21 28 views
0

我試圖跟蹤任意數量的子組件。反應:創建和引用動態組件參考

通常你只需要引用this.refs.refName,但在我的情況下,我有一個任意數量的需要跟蹤的ref。

這裏有一個簡明的例子:

var NamesList = React.createClass({ 
    getAllNames: function() { 
    // Somehow return an array of names... 

    var names = []; 
    this.refs.????.forEach(function (span) { 
     names.push(span.textContent); 
    }) 
    }, 

    render: function() { 
    var names = ['jack','fred','bob','carl']; 
    var spans = []; 

    names.forEach(function (name) { 
     spans.push(<span contentEditable={true} ref='?????'>name</span>); 
    }); 

    return (
     <div> 
     {spans} 
     </div>; 
    ); 
    } 
}); 

ReactDOM.render(<NamesList></NamesList>, mountNode); 

如果我接近問題錯誤地讓我知道。我期望的結果是將數據從RESTful服務傳遞到React組件,允許用戶編輯該數據,並在需要時再次導出。我一直無法在React refs文檔中找到答案。

回答

1

下保持參到每個跨度的陣列的內部稱爲this.spans

此操作,因爲每個跨度增加本身使用addSpanRef方法裁判陣列。

getAllNames然後遍歷所有引用的跨度並抓取它們的textContent。

如果你有子組件(而不是跨度),你可以在這些子節點上調用方法!

var NamesList = React.createClass({ 

    // returns an array of names 
    getAllNames() { 
    return this.spans.map((span) => span.textContent); 
    }, 

    // Add to our spans refs array 
    addSpanRef (node) { 
    this.spans = [...this.spans, node]; 
    }, 

    render: function() { 
    this.spans = []; // create the spans refs array 
    var names = ['jack','fred','bob','carl']; 

    // Save a ref to "this" for the forEach loop 
    var thisRef = this; 
    names.forEach(function (name) { 
     spans.push(<span contentEditable={true} ref={thisRef.addSpanRef}>name</span>); 
    }); 

    return (
     <div> 
     {spans} 
     </div>; 
    ); 
    } 
}); 

ReactDOM.render(<NamesList></NamesList>, mountNode); 
1

1.快速和骯髒的解決方案:在容器組件通讀裁判的名字讀所有名稱

一種方法是把一個裁判在容器上,並閱讀的TextContent上childNode跨越。

componentDidMount: function() { 
    var elem = this.refs.container.getDOMNode(); 
    var nameNodes = elem.children; 
    var names = []; 
    for (var i=0; i<nameNodes.length; i++) { 
     names.push(nameNodes[i].textContent); 
    } 
    console.log(names); 
    }, 

你可以找到Working codepen of this here

警告:上面的代碼很髒:用戶可以在不知道DOM更改的情況下更改span的內容。這是一個(非常)壞主意

2.清潔方案

所以,你需要的狀態:用戶可以改變跨度的內容,並作出反應需要了解它。
因爲您還需要所有(新)編輯名稱的數組,此狀態需要駐留在容器級別。
以下是純粹的<EditableSpan>組件的解決方案,每次更改名稱時都會在其父級上調用方法。

var EditableSpan = React.createClass({ 
    onChange: function() { 
    var newContent = event.target.textContent; 
    this.props.onChange(this.props.index, newContent); 
    }, 
    render: function() { 
    return <span 
      contentEditable={true} 
      onInput={this.onChange}> 
     {this.props.name}</span> 
    } 
}); 

請注意,這清晰的解決方案不再使用裁判,因爲它們不需要:所有的數據是衆所周知的反應,所以反應並不需要裁判從DOM閱讀。相反,它會在每次更改時讀取event.target以更新容器狀態。您可以在這裏找到full working codepen

警告:對於此解決方案,我添加了快速和骯髒的keys(名稱)。 React需要唯一的鍵(而不是索引)。因爲列表中的名稱不能保證是唯一的,所以您可能需要另一個更智能的解決方案(創建ID或時間戳)。

+0

對不起,我試圖動態地拉動跨度的名字__。看起來您所做的更改是關於動態設置跨度。在僞代碼中:對於每個跨度,抓取textContent並將它們作爲數組返回。這有助於解釋我在問什麼? – joshuakcockrell

+0

用2種解決方案更新了答案。請注意,第二個解決方案確實會返回一個帶有跨度textContent的數組,但不使用refs。 React是並且應該是textContent的唯一所有者和管理者。所以它不是必需的(和buggy /不可管理的代碼的來源)使用refs來獲取名稱。 – wintvelt