---
status: "published"
title: "React: Injecting Component Props with ES7 Decorators"
date: "2018-08-20"
description: "Experimenting with decorators to make writing and maintaining React components more ergonomic (subjectively)."
image: "https://github.com/user-attachments/assets/07989c52-ef37-4619-9696-c05f040bb65a"
imageAlt: "Photo by Thomas AE on Unsplash"
author: "Vlad Sabev"
authorUrl: "https://github.com/vdsabev"
authorAvatar: "https://github.com/vdsabev.png"
tags: ["javascript","react","software development"]
navigationIndex: 0
---

Photo by [Thomas AE](https://unsplash.com/@thomasae?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com/?utm_source=medium&utm_medium=referral)

While I'm sure many prefer to stick to more traditional ways of writing components, I often try to bring some features that make sense from one framework to the other — in this case, Preact's injection of `props` and `state` into a component's `render` method.

> **Disclaimer:** after reading through [this GitHub issue](https://github.com/facebook/react/issues/1387) I've decided to stop using the `@Inject` decorator in favor of parameter destructuring:

```javascript
class UserLink extends Component {
  ...
  render({ user } = this.props, { showTooltip } = this.state) {
    return (...);
  }
}
```

> This works exactly the same as the decorator while having the benefit of not needing to import an external utility function.
> 
> I think this article still has some value, and at the very least should help people understand the original problem I was trying to solve. If you're still interested, keep reading *😉*

## 🤹‍ Skills

To effectively follow along with this article, you'll need knowledge of:

- JavaScript — intermediate
- React/Preact— intermediate

## ⭕ Stateless Component

Let's start with a regular stateless component — in this case, displaying the link to a user. It accepts an object containing the ID, first name, and last name:

```jsx
const UserLink = ({ user }) => (
  <a
    className="userLink"
    href={`http://twitter.com/${user.id}`}
    title={`${user.firstName} ${user.lastName}`}
  >
    @{user.id}
    <div className="userLink-tooltip">
      {user.firstName} {user.lastName}
    </div>
  </a>
);
```

If we put a `<main></main>` element in the HTML template, we can render the component like this:

```javascript
ReactDOM.render(
  <UserLink user={{ id: 'vdsabev', firstName: 'Vlad', lastName: 'Sabev' }} />,
  document.querySelector('main')
);
```

The component displays the user's ID, and on hover also shows the full user name in a tooltip. Here's a CodePen:

<iframe height="450" style="width:100%;" scrolling="no" title="" src="https://codepen.io/vdsabev/embed/EeYzRG?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

## 🔴 Class Component

As a component evolves, its requirements change. We often rewrite stateless function components to class components and vice versa.

Now our designer comes back with a fresh design idea — instead of on hover, we will show the tooltip when clicking a small button on the side.

To do this, we need internal state and so rewrite the component as a class:

```javascript
class UserLink extends Component {
  state = {
    showTooltip: false,
  };

  toggleTooltip = () => {
    this.setState((state) => ({ showTooltip: !state.showTooltip }));
  };

  render() {
    return (
      <a
        className="userLink"
        href={`http://twitter.com/${this.props.user.id}`}
      >
        @{this.props.user.id}
        <div
          className="userLink-tooltip"
          style={{ opacity: this.state.showTooltip ? 1 : 0 }}
        >
          {this.props.user.firstName} {this.props.user.lastName}
        </div>
        <span className="userLink-button" onClick={this.toggleTooltip}>💬</span>
      </a>
    );
  }
}
```

And here's another CodePen:

<iframe height="450" style="width:100%;" scrolling="no" title="" src="https://codepen.io/vdsabev/embed/wEwZba?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true"></iframe>

## 🔨 Refactoring

There are lots of references to `this` in the class component's `render` method which make it significantly more verbose. Also, if we decide to move the user from `this.props` to `this.state` for whatever reason, we would rewrite all those references as well.

To ease the transition between stateless and class component, we can use the neat [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) syntax. Notice how in the next `render` method references to `this.props` and `this.state` are isolated to the top, while JSX is essentially the same as in the stateless component:

```javascript
class UserLink extends Component {
  ...
  render() {
    const { user } = this.props;
    const { showTooltip } = this.state;
    return (
      <a
        className="userLink"
        href={`http://twitter.com/${user.id}`}
      >
        @{user.id}
        <div
          className="userLink-tooltip"
          style={{ opacity: showTooltip ? 1 : 0 }}
        >
          {user.firstName} {user.lastName}
        </div>
        <span className="userLink-button" onClick={this.toggleTooltip}>💬</span>
      </a>
    );
  }
}
```

There's also an even neater way to destructure an object with nested properties:

```javascript
render() {
  const {
    props: { user },
    state: { showTooltip },
  } = this;
  return (...); // Same JSX as before
}
```

> *📝* Technically, we can destructure objects on a single line, like this:
> 
> `const { props: { user }, state: { showTooltip } } = this;`
> 
> However, [Prettier](https://prettier.io) (which I use in every project) insists on formatting nested destructuring as multiple lines.

This already looks better, and yet — could we keep `props` and `state` destructuring in the signature of the `render` method?

## ⚛ Preact

That is, in fact, exactly what [Preact](https://preactjs.com) does by default. [Example from the docs](https://github.com/developit/preact/tree/e30cc390d37d5eaaf2a86316ea4086580631a40d#examples):

```javascript
class Link extends Component {
  render(props, state) {
    return <a href={props.href}>{props.children}</a>;
  }
}
```

Preact calls the component's `render` method with `this.props` as the first argument and `this.state` as the second, saving us some work!

However, many projects use React instead of Preact, and will continue doing so. And if we used this Preact feature and then switched to React would we really want to rewrite all of our `render` methods?

How do we get the same behavior with minimal effort then?

> *📝 While e*xtending the base `*React.Component*` class and overriding the `*render*` method seems like an obvious solution at first, you're likely to bump into weird errors, and [the React docs generally encourage using composition over inheritance](https://reactjs.org/docs/composition-vs-inheritance.html).
> 
> Do let me know if you've seen someone figure this out!

## 💉 Inject

While looking for alternatives, I stumbled upon [an article](https://medium.com/@goncalvesjoao/react-es7-decorators-how-to-inject-props-to-your-render-method-27a0a7973106), then [this set of helper functions](https://github.com/goncalvesjoao/relpers/blob/1d122039ad6a7ee8966ff70ac3f13b6eb9b64dfc/src/injectProps.js), which ultimately lead me to an answer:

```javascript
const Inject = (...keys) => (target, propertyKey, descriptor) => {
  const originalMethod = descriptor.value;

  if (typeof originalMethod !== 'function') {
    throw new SyntaxError(`@Inject can only be used on class methods, not: ${originalMethod}`);
  }

  return {
    ...descriptor,
    value(...args) {
      const values = keys.map((key) => this[key]);
      return originalMethod.apply(this, [...values, ...args]);
    },
  };
};

export default Inject;
```

This function modifies a class method to call the original method it was applied on with some predefined properties of the instance object `this`.

Here's a usage example:

```javascript
class UserLink extends Component {
  ...
  @Inject('props', 'state')
  render({ user }, { showTooltip }) {
    return (...); // Same JSX as before
  }
}
```

Unlike Preact's behavior, the `Inject` decorator is explicit — it can inject any arbitrary property of the class component at any parameter position. In this case it mimics Preact in that it injects `this.props` as the first parameter and `this.state` as the second parameter. Then we can destructure them right there in the method signature!

> *📝* If you've ever used Angular, then you know dependency injection, and `Inject` looks a lot like it.

## 🤙 Trade-offs

The main advantage here is using the `Inject` decorator makes render code more flexible. This means we can refactor components fearlessly while keeping our views unchanged and managing `props` and `state` at the edges of the `render` function (i.e. in the method signature).

The main disadvantage is we have to import the `Inject` decorator everywhere we use it, and it adds a bit of **magic** to every component we write. And for every bit of **magic** we add to our code base, a new developer on the team might have some trouble understanding and using it, even if it's well documented.

Also, if we're rewriting an existing Preact code base into React, the decorator isn't an ideal solution, as we still have to inject `props` and `state` into the render method of every single component!

Finally, as of the writing of this article, decorators are still a [Stage 2 experimental feature](https://github.com/tc39/proposals), so use them with caution!

## 🏁 Conclusion

What do you think — would you use something like the `Inject` decorator, or stick to more stable and straightforward JavaScript features like assignment with destructuring?

Do you regularly use any other decorators or utility functions when writing React components?

