Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React access Dom Nodes from this.props.children

Tags:

reactjs

Let's say I have a Card that contains a login Form

 <Card>
     <LoginForm/>
 </Card>

How do I access the nodes from the Form within the Card render function?

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

Because what i´d like to do is to render the submitbutton not within the props.children context but render it wrapped outside of the given 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>)

example expected result

There are some components which actually do what I want. For example the Tabs component from react-toolbox. They somehow manage to render what's within the Tab (children) somewhere else

Just for instance

   <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 lead to the following html rendered html example

As you can see the children from the tab where rendered within their own section I do not want to change anything on the Form to solve this problem, I would like to pass the Form into the Card and let the Card decide how the Form will be rendered within the card render function.

Since I'm trying to implement the Google Material Design Card component and just use it as a template there are more elements coming which will need to be split up and placed at the positions I want them to be. The thing is I could actually place the relevant HTML around the Form to get it as the Card I want it to be, but then I wouldn't need the component at all.

like image 804
Snackaholic Avatar asked Feb 22 '17 09:02

Snackaholic


People also ask

How do you get child nodes in React?

children should either be a ReactElement or an array of ReactElement, but not components. To get the DOM nodes of the children elements, you need to clone them and assign them a new ref. You can then access the child components via this. refs[childIdx] , and retrieve their DOM nodes via ReactDOM.

How do you access the DOM element in React?

In React we can access the DOM element using Refs. Refs provide a way to access DOM nodes or React elements created in the render method. Creating Refs: Refs are created using React. createRef() and attached to React elements via the ref attribute.


1 Answers

There are some decent answers here, but none of them directly answer your question. Therefore, even though you should refactor your code (as elucidated below), I am going to provide you 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 a property on the instance, you can then access that property from children by using a ref. I checked for typeof === object here, because there was only one child.

WARNING: this code is NOT PRODUCTION READY. Do not ever run this in production. The code I have demonstrated is a terrible hack, and you should never try this at home.


like image 189
natnai Avatar answered Oct 04 '22 11:10

natnai