Respond to access to Dom Nodes from this .props.children

Say I have a card containing a registration form

<Card> <LoginForm/> </Card> 

How do I access nodes from a form in a map render function?

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

Because I would like to make submitbutton not in the context of props.children, but to make it wrapped outside this child!

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

expected result example

There are some components that really do what I want. For example, the Tabs component from react-toolbox . They somehow contribute to the fact that inside the Tab (children) somewhere else

Just for example

  <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> 

Which will result in the following html rendered html example

As you can see the children from the tab where they are displayed in their own section I don’t want to change anything in the form to solve this problem, I would like to transfer the form to the Map and let the Map decide how the Form will be displayed in the map rendering function.

As I try to implement the Google component Material Design Map and just use it as a template, there are more elements that need to be divided and placed in the positions that I want them to be. The fact is, I could place the corresponding HTML code around the Form to get it as the map I want, but then I will not need the component at all.

+6
source share
4 answers

There are some decent answers here, but none of them directly answer your question. Therefore, although you should reorganize your code (as explained below), I am going to provide you with a working solution:

 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

By setting the property on the instance, you can access this property from children using ref . I checked here typeof === object , because there was only one child.

WARNING: this code DOES NOT PRODUCE READY. Never run it in production. The code I demonstrated is a terrible hack, and you should never try to do this at home.


+3
source

If you are trying to submit a form, perhaps look at sending the onChange event and storing the value (depending on the field name) in the Map state. Then attach the onChange event on the inputs so that as soon as they are updated, the data will be transferred back to the container for sending.

0
source

If you want to split past children, you can just filter the child array to separate the children, however your children seem to be nested.

Why don't you allow children to share cards between the inner container and other content?

I think that restructuring in this case is more suitable than changing the passed child property.

In addition, pulling the submit button out of the actual form tags will break the form because it will no longer be submitted without any custom connection between the button and the actual form.

0
source

Do not try to manipulate the DOM; this is generally an anti-reagent pattern (although there are several valid use cases). In your case, instead of literally trying to move the elements, I just hide the button in the form and add it to the parent.

Assuming you have access to the internals of <LoginForm> , you can add a support to hide the button:

 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> 

Add a button to the Card component:

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

Finally, at your parent:

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

All that has been said, it really seems that you need to better structure your code and break some of these components into smaller and reusable fragments. For example, the Card component should probably not affect the style of a button or conditionally render children; he should just add a frame around any children. You can then create a more complex component that will compose these simpler subcomponents so that everything you need.

-one
source

Source: https://habr.com/ru/post/1015176/


All Articles