13

I may have missed something, but here goes. If I have:

var Swoosh = React.createClass({
  render: function() {
    return (
      <div className="swoosh">
        Boom.
      </div>
    );
  }
});

React.renderComponent(
  <Swoosh />,
  document.getElementById('content')
);

Can I set props as attributes on the mount point (where id='content')?

<div id='content' foo='alice' bar='has' bav='a cat' />
<!-- have foo, bar & bav available as props in <Swoosh />? -->
Dmitry Shvedov
  • 3,169
  • 4
  • 39
  • 51
maligree
  • 5,939
  • 10
  • 34
  • 51

4 Answers4

26

No, though of course you can do:

var container = document.getElementById('content');
React.renderComponent(
  <Swoosh
    foo={container.getAttribute('foo')}
    bar={container.getAttribute('bar')}
    bav={container.getAttribute('bav')} />,
  container
);

(or if you want to make an attributes dict using something like https://stackoverflow.com/a/5282801/49485, then you can do Swoosh(attributes)).

Community
  • 1
  • 1
Sophie Alpert
  • 139,698
  • 36
  • 220
  • 238
  • 1
    I accepted the other answer, but I feel this one should get just as much rep. Thanks! – maligree Feb 11 '14 at 11:37
  • I wrote the Mixin as an exercise. It works, but I think Ben's answer is better advice in the long run. The Mixin bridges you from DOM into React, but you'll have an easier time if you go all React all the time. – Ross Allen Feb 11 '14 at 16:19
  • The question seemed like a trival test case to which this solution would be better. However, this is not really a good answer as it requires you to know in advance what every component will need. What if you want to abstract this to a utility function? You can't predict what the attributes will be and this encourages creating lots of boilerplate just to pass arbitrary attributes. – pho3nixf1re Oct 02 '15 at 16:07
7

There's nothing in the API to transfer properties from a plain DOM element to a React component, but you could create a Mixin to do it. Note that this will only work on a component passed to renderComponent because it uses setProps:

(Working JSFiddle)

var InheritsDomAttributes = {
  componentDidMount: function(rootNode) {
    var hasNextProps = false;
    var nextProps = {};
    var parentNode = rootNode.parentNode;

    Object.keys(parentNode.attributes).forEach(function(key) {
      var namedNode;

      // NamedNodeMaps have an attribute named "length" that
      // should not be considered a set attribute.
      if (key !== "length") {
        hasNextProps = true;
        namedNode = parentNode.attributes[key];
        nextProps[namedNode.name] = namedNode.value;
      }
    });

    if (hasNextProps) this.setProps(nextProps);
  }
};

var Swoosh = React.createClass({
  mixins: [InheritsDomAttributes],
  render: function() {
    return (
      <div className="swoosh">
        Boom.
      </div>
    );
  }
});

React.renderComponent(
  <Swoosh />,
  document.getElementById('content')
);
Ross Allen
  • 43,772
  • 14
  • 97
  • 95
6

There is a alternative way to achieve this by using data attributes in html. Here's a small example: In html, you add as much properties with the data prefix as you want:

<div id="root" data-prop-one="Property one" data-prop-two="Property two"/>

All data properties will be automatically converted to CamelCased properties in the element's dataset property. Pass this property to your React component and you're done:

let element = document.getElementById('root')
ReactDOM.render(<App myPropsObject={element.dataset}/>, element)
Dany Dhondt
  • 881
  • 9
  • 27
0

This behavior is exactly what web-components were designed for, with this lib:

https://github.com/bitovi/react-to-web-component

You can convert your react app to a web-component, and then just set attributes easily, like:

const Greeting = ({ myName }) => {
  return <h1>Hello, {myName}!</h1>
}

const WebGreeting = r2wc(Greeting, {
  props: {
    myName: "string",
  },
})

<body>
  <h1>Greeting Demo</h1>

  <web-greeting my-name="Justin"></web-greeting>
</body>
chrismarx
  • 11,488
  • 9
  • 84
  • 97