1.0.1 • Published 6 years ago

proper-component v1.0.1

Weekly downloads
1
License
MIT
Repository
-
Last release
6 years ago

proper-component

Pass props to third-party React components, whether they expect them or not.

Usage

Say you want to use this third-party component...

import React from 'react';

class Component extends React.Component {
  render() {
    return (
      <div className="component" style={{ color: 'tomato', fontStyle: 'italic' }}>
        {this.props.children}
      </div>
    );
  }
}

export default Component;

...but it doesn't allow forwarding of props it doesn't care about (stopping you from adding things like ids or aria-*/data-* attributes), nor does it allow you to apply any extra classes or styles.

import React from 'react';
import { render } from 'react-dom';
import Component from 'third-party/Component';

render(
  <Component
    title="aww"
    className="utility-class"
    style={{
      color: 'thistle',
      fontWeight: 'bold'
    }}>
    Aww 😿
  </Component>,
  document.body
);

...will render[1]:

<div class="component" style="color:tomato;font-style:italic">
  Aww 😿
</div>

Well, that sucks.

Now lets use proper-component to make a higher order component from Component, and suddenly, your wildest dreams become possible:

import React from 'react';
import { render } from 'react-dom';
import Component from 'third-party/Component';
import proper from 'proper-component';

const ProperComponent = proper(Component);

render(
  <ProperComponent
    title="yay"
    className="utility-class"
    style={{
      color: 'thistle',
      fontWeight: 'bold'
    }}>
    Yay 🎉
  </ProperComponent>,
  document.body
);

...will render[1]:

<div title="yay" class="component utility-class" style="color:thistle;font-style:italic;font-weight:bold">
  Yay 🎉
</div>;

(...yay)

Installation

npm install proper-component

FAQs / Notes

  • You technically shouldn't be messing with components in this way, because you're breaking encapsulation and responsibility principles and yadda-yadda (zzzZZZzzz), but here's another way of looking at it: If not being able to forward props was the only reason you were ruling out a third party component library in your app, well, this is a win for everyone, isn't it?
  • Under the hood, refs are being forwarded correctly, so they're on the original component, not the HOC. Non-React static class methods are copied to the HOC too (thanks (hoist-non-react-statics)https://github.com/mridgway/hoist-non-react-statics);
  • Currently, your className will be appended if one already exists on the element and your style will be merged with anything that currently exists. All other props are forwarded.
  • Yes, this works for stateless function components too.
  • If you're using React's dev tools in Chrome, you can see how the magic HOC / ref-forwarding stuff works (the component displayNames are a giveaway. Or you can just read the source in /src/lib/index.js. It's only a few lines.
  • To get your head around what proper is doing, imagine it just effectively rewrote the third party component example from above as:
class ProperComponent extends React.Component {
  render() {
    const {className = '', style = {}, children ...props} = this.props;

    return (
      <div
        className={`component ${className}`}
        style={{ color: 'tomato', fontStyle: 'italic', ...style }}
        {...props}>
        {children}
      </div>
    );
  }
}

Maybe we can get third-party component library maintainers to do this in the first place, and we wouldn't be in this situation in the first place. I look forward to proper-component's reduncancy 🤞.

.component {
  margin-bottom: 12px;
  border: 2px solid currentColor;
  padding: 6px 10px;
  background-color: papayawhip;
  font-family: sans-serif;
}
.utility-class {
  background-color: rebeccapurple;
}

Contributing

PRs are most welcome on GitHub!

If you clone this project & npm install its development dependencies, you can run tests with npm test and and hack on anything under /src.

I've not gotten around to seeing how this plays with project-specific development setups what use stuff like TypeScript/Flow, or PropTypes checking, so I'd love it if you shared your experiences, or throw a fix my way. Everybody benefits!

Authors