React: Can I add attributes to children's resu

2019-07-24 08:05发布

问题:

I have a component that wraps other components:

class MyComp extends React.Component {
  render() {
    return <div> {this.props.children} </div>
  }
}

Let's say I add another random component as a child:

<MyComp><FancyP>Hello</FancyP></MyComp>

The resultant HTML would be like this:

<div>
  <p class="fancy'>Hello</p>
</div>

I know that using React.Children I could add new props to the child component, but what I really want to do is add custom attributes to the resultant HTML of any random child, having something like this:

<MyComp childAttr={{'data-x':'value'}}><FancyP>Hello</FancyP></MyComp>

that would generate the following:

<div>
  <p class="fancy' data-x='value'>Hello</p>
</div>

Is there a way to achieve this? Adding a props to the children does not work because children's classes are not aware of the new props and they ignore them.

回答1:

Not sure why you need this and I do recommend you to rethink your architecture before it is too late.

But you can do a little bit of a hackery using ReactDOM.findDOMNode.

First you need to set refs for every child component. By cloning element and assigning a ref.

Then attach hooks on componentDidMount and componentDidUpdate events, find dom element using findDOMNode and manually populate dataset. DEMO.

import React, { Component, Children, cloneElement } from 'react'
import { render, findDOMNode } from 'react-dom'

class MyComp extends Component {
  componentDidMount() {
    this.setChildAttrs()
  }

  componentDidUpdate() {
    this.setChildAttr()
  }

  setChildAttrs() {
    const { childAttrs } = this.props
    const setAttrs = el => Object.keys(childAttrs)
      .forEach(attr => el.dataset[attr] = childAttrs[attr])

    // for each child ref find DOM node and set attrs
    Object.keys(this.refs).forEach(ref => setAttrs(findDOMNode(this.refs[ref])))
  }

  render() {
    const { children } = this.props
    return (<div> {
        Children.map(children, (child, idx) => {
          const ref = `child${idx}`
          return cloneElement(child, { ref });
      })} </div>)
  }
}