2017-02-22 57 views
6

陣營訪問DOM節點比方說,我有一個包含登錄表單從this.props.children

<Card> 
    <LoginForm/> 
</Card> 

如何訪問節點從形式在卡中的渲染功能的卡?

<Form > 
    <input type="text" name="email"/> 
    <input type="password" name="password"/> 
    <input type="submit"/> 
</Form> 

因爲我想要做的就是呈現submitbutton不在props.children上下文中,但將它提交給給定孩子之外!

render() { 
return (
    <div className="card"> 
     <div className="inner"> 
     {/* render Children */} 
     {this.props.children != undefined ? 
      <div className="childrenWrapper"> 
      {this.props.children} 
      </div> 
      : "" 
     } 
     </div> 
     {/* render submit from login form here, not above */ 
    </div>) 

example expected result

其中有一些組件實際上做我想做的。例如react-toolbox中的Tabs組件。它們在某種程度上設法使標籤(兒童)之內有什麼別的地方

就比如

<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse> 
     <Tab label='First'><small>First Content</small></Tab> 
     <Tab label='Second'><small>Second Content</small></Tab> 
     <Tab label='Third'><small>Third Content</small></Tab> 
     <Tab label='Disabled' disabled><small>Disabled Content</small></Tab> 
    </Tabs> 

這將導致以下HTML rendered html example

你可以從標籤看孩子在他們自己的部分中提交 我不想在表單上更改任何內容來解決此問題,我想將表單傳遞給卡片並讓卡片決定如何在卡片呈現功能中呈現表格。

由於我試圖實施Google Material Design卡片component並將其用作模板,因此還有更多要素需要拆分並放置在我希望的位置。事情是我實際上可以在表單中放置相關的HTML來獲得它作爲我想要的卡片,但是我根本不需要該組件。

+0

如何用flatButton設置一個變量,然後將它作爲道具傳遞給卡片組件?啊,我忘了:要訪問flatButton,我想你可以使用ref道具。 – dschu

+0

@dschu工作出來,但事情是扁平按鈕本身是在形式之內,然後將呈現在兒童部分以及 – TeaTime

+0

是的,你是對的。您將不得不將另一個prop傳遞給LoginForm組件,以告訴組件不呈現按鈕。在這種情況下,您應該考慮重組您的組件。 – dschu

回答

3

這裏有一些體面的答案,但沒有一個直接回答你的問題。因此,即使你應該重構你的代碼(如下面解釋),我會爲您提供一個有效的解決方案:

class Card extends React.Component { 
    constructor() { 
    super(); 
    this.state = {}; 
    } 

    render() { 
    console.log(typeof this.props.children) 
    return (
     <div> 
     {typeof this.props.children === 'object' 
      ? React.cloneElement(this.props.children, { ref: (n) => this.form = n }) 
      : null} 
     <button onClick={(e) => console.log(this.form.data)}>submit</button> 
     </div> 
    ); 
    } 
} 

class Form extends React.Component { 
    constructor() { 
    super(); 
    this.onChange = this.onChange.bind(this); 
    this.state = {}; 
    } 

    onChange(e) { 
    this.data = e.target.value; 
    } 

    render() { 
    return (
     <form> 
     <input type="text" onChange={this.onChange} /> 
     </form> 
    ); 
    } 
} 

ReactDOM.render(
    <Card><Form /></Card>, 
    document.getElementById('container') 
); 

https://jsbin.com/fohehogozo/edit?js,console,output

通過對實例設置屬性,你就可以訪問通過使用ref從兒童財產。我在這裏檢查了typeof === object,因爲只有一個孩子。

警告:此代碼不是生產準備就緒。永遠不要在生產中運行這個。我已經證明的代碼是一個可怕的黑客,你不應該在家裏嘗試這個。


+0

爲什麼我不應該使用這個解決方案,因爲它似乎是確定我的孩子類型的唯一方法?我的意思是,在這種情況下,我可以期待即將到來的孩子們,因爲我可以簡單地將他們作爲屬性交給他們,並如下所述使用他們。但是如果我不能指望新來的孩子呢?爲什麼不是一個好的解決方案呢? – TeaTime

+1

我寫了兩杯葡萄酒時,可以清理很多代碼。但是儘管如此,這聽起來似乎很簡單,儘管人們可以很容易地看到這樣的代碼可能難以維護。如果可以的話,重構一個更習慣的解決方案是有意義的。出於某種原因,逃生艙口被稱爲逃生艙口。 – natnai

0

如果您嘗試提交表單,可能會查看傳遞onChange事件並在卡片狀態中存儲值(基於字段名稱)。然後在輸入中添加onChange事件,一旦它們更新,數據將被傳回容器供您提交。

+0

實際上我試圖從卡類中的另一個地方的表單類渲染一部分 – TeaTime

+1

只是出於興趣,你爲什麼需要這樣做?它似乎是一個代碼味道 –

+0

,因爲我想要正常呈現表單,如果使用不同的卡風格。不幸的是,我不得不改變HTML佈局,以及我有點卡在那裏 – TeaTime

0

如果你想分割通過的兒童,你可以簡單地過濾兒童數組來分裂兒童,但是你的兒童似乎是嵌套的。

爲什麼你不讓卡兒童處理你的inner容器和其他內容之間的分隔?

我認爲在這種情況下重組更適合修改傳遞的子屬性。

此外,將提交按鈕從實際的表單標記中拉出,會破壞表單,因爲如果沒有按鈕和實際表單之間的某種自定義連接,它將不再提交。

-1

不要試圖操縱DOM;它通常是React中的反模式(儘管有一些有效的用例)。在你的情況,而不是字面上試圖移動的元素,我只是隱藏在窗體中的按鈕,並將其添加到父項。

假設你有機會獲得的<LoginForm>的內部,你可以添加一個道具隱藏按鈕:

const button = 
    <div class="flatbuttonWrapper"> 
    <input type="submit"/> 
    </div>; 

<Form> 
    <input type="text" name="email"/> 
    <input type="password" name="password"/> 
    {!this.props.hideButton && button} 
</Form> 

添加的按鈕Card組件:

render() { 
    return (
    <div className="card"> 
     <div className="inner"> 
     {this.props.children != undefined ? 
      <div className="childrenWrapper"> 
      {this.props.children} 
      </div> 
      : "" 
     } 
     </div> 
     <div class="flatbuttonWrapper"> 
     <input type="submit"/> 
     </div> 
    </div> 
); 
} 

最後,在父母:

<Card> 
    <LoginForm hideButton /> 
</Card> 

這一切都說,它真的感覺就像你需要更好地構建你的代碼並將這些組件分解成更小,更可重用的組件一樣。例如,Card組件可能不應該影響按鈕的樣式或有條件地呈現子項;它應該只是爲任何孩子添加一個框架。然後,您可以創建一個更復雜的組件,將這些更簡單的子組件組合成任何您需要的組件。