ccnokes ccnokes - 5 days ago 6
React JSX Question

What is the React equivalent of an Angular directive that only works on attributes?

For example you could have a directive in angular like so:

angular.module('app')
.directive('classy', function() {
return {
restrict: 'A',
link: function($scope, $el) {
$el.addClass('stay-classy');
}
}
}


And implement like so:

<div classy></div>


There doesn't seem to be an equivalent in React that I've seen after reading through most the docs and googling. I was hoping for something like:

...
render: function() {
return (
<MyComponent classy></MyComponent>
);
}


Is there something like that possible that I've been missing? Is there a different yet functionally similar equivalent? Or maybe this question just shows that I'm missing some part of the "React way" and I shouldn't ever want to do this. Thanks!

Answer

It will be helpful to consider what Angular and React are each doing "behind the scenes."

In your Angular example, when you write <div classy/></div> you're saying "render a DIV element and then attach to it the behaviors defined by the classy directive.

In your React example, when you write <MyComponent classy></MyComponent>, you're saying, "create an instance of MyComponent and pass it the props { classy: true }. The transpiler (Babel or whathaveyou) will turn it into the following JavaScript:

React.createElement(MyComponent, { classy: true });

So the answer to your question is that you can't write <MyComponent classy></MyComponent> because MyComponent component doesn't know what to do with the classy prop. In React, you might write something like this instead:

class ClassyDiv extends React.Component {
  render() {
    const { className, ...rest } = this.props;
    return <div className={`${className || ''} stay-classy`} {...rest}/>;
  }
}

This works because we know the React.DOM.div component (like most DOM components) knows what to do with the className prop.

Since React 0.14 we can express something like this more simply, as a "pure" stateless functional component, i.e. a function that accepts props and returns the rendered result:

function AlsoClassyDiv(props) {
  const { className, ...rest } = props;
  return <div className={`${className || ''} stay-classy`} {...rest}/>;
};

You can see both approaches in action in the below snippet.

class ClassyDiv extends React.Component {
  render() {
    const { className, ...rest } = this.props;
    return <div className={`${className || ''} stay-classy`} {...rest}/>;
  }
}

function AlsoClassyDiv({ className, ...props }) {
  return <div className={`${className || ''} stay-classy`} {...props}/>;
};

ReactDOM.render(
  <div id="container">
    <div>Regular div</div>
    <ClassyDiv>ClassyDiv!</ClassyDiv>
    <AlsoClassyDiv>AlsoClassyDiv!</AlsoClassyDiv>
  </div>,
  document.body
);
.stay-classy { font: bold 3em Helvetica; text-shadow: 4px 4px 2px #aaa; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>