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

25,678

Solution 1

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>

Solution 2

One way you could implement similar behavior is using React class mixins

Solution 3

A great example of a useful directive in angular is

<a href="#target" class="smooth-scroll">Target</a> 

The smoothScroll directive would intercept the click event then use window scroll or jquery scrollTo to apply all manner of animation.

Anywhere in the html one could then simply use the directive powered class name.

This sort of thing is not available in React. To do it in React you would have to create a special link component to use instead of:

<a> like ASmooth....
Share:
25,678
ccnokes
Author by

ccnokes

Cheesecake aficionado. JavaScript developer. I made some Egghead videos: https://egghead.io/instructors/cameron-nokes.

Updated on November 14, 2021

Comments

  • ccnokes
    ccnokes over 2 years

    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!

  • ccnokes
    ccnokes about 9 years
    +1 for "in Angular you write HTML and then Angular attaches behaviors to it, but in React you write components...and React generates DOM elements from them". That's a good explanation that illustrates one of the fundamental principles of React and I think would be helpful for anyone transitioning from Angular to React. Thanks!
  • Cody
    Cody about 8 years
    Sounds like Mixins are on their way out -- but (+1) for stating what nobody else has even glanced on.
  • psycho brm
    psycho brm over 7 years
    "they're really just JavaScript—and React generates DOM elements from them" - So basically they are components that represent DOM elements, yet they are not DOM elements, they only result into DOM elements. Dude.. React's inverse thinking got to you.
  • Stanislav Šolc
    Stanislav Šolc over 7 years
    I wouldn't call it high order component at all, your example is just simple specialization by parent component. High order component is slightly different patern...
  • Jordan Running
    Jordan Running over 7 years
    @StanislavŠolc It's worth noting that this answer was written pre-React 0.14. Would you say that the following, an equivalent React 0.14 pure function component, is a HOC? const ClassyDiv = props => <div className={`${props.className || ''} stay-classy`}/>;
  • Jordan Running
    Jordan Running over 7 years
    @StanislavŠolc To clarify, I'm asking sincerely. I think you're right that my answer is a bit muddled with regard to HOCs, so if you have any suggestions on how to improve it I'd appreciate it. Can I clarify the bit about HOCs or should I omit it entirely?
  • Miguel Felipe Guillen Calo
    Miguel Felipe Guillen Calo almost 6 years
    In angular you can attach multiple directives on elements, is this possible in react? e.g. <div draggableEl="" highlightOnMouseDown trackOnEvent="click">Drag me!</div>
  • Bruno Finger
    Bruno Finger over 5 years
    While I agree with you on "To do it in React you would have to create a special link component", in Angular(/JS) you have to create a special attribute directive to attach this behavior to your anchor element. At the same time, your newly created special React link component could render an anchor element in the end as well, with the same behavior attached to it. In the end we get the same result, potatos potatoes.
  • Jens
    Jens over 5 years
    @BrunoFinger The whole point of directives is composability. First: you can apply a directive to any component, even components included from other libraries. Second: you can apply multiple directives to the same component. Directives are decorators, so it's not the same thing.
  • Joel Davey
    Joel Davey over 3 years
    There is no equivalent in React this is a feature only Angular has, the example in this answer does not cover the full context of how directive's work in Angular I could add 'classy' to any element without the need to pass props down.