npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@benwiley4000/bind-cache

v0.1.3

Published

Bound method cache, ideal for React

Downloads

12

Readme

bind-cache

Creates a cache of bound JavaScript functions created with Function.prototype.bind.

  • Only one instance is ever created for each unique set of arguments
  • Designed to be allocated only for the lifetime of an associated object
  • Works for binding call arguments to a method
  • Ideal for React components
  • 1.27 KB (unminfied)

usage

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.message = 'Hello World';

    // cache is garbage-collected whenever the
    // MyComponent instance is garbage-collected
    this.bind = bindCache(this);
  }

  handleClick() {
    alert(this.message);
  }

  render() {
    // across multiple renders, only one bound instance of this.handleClick
    // is ever created for this instance of MyComponent
    return <MyButton onClick={this.bind(this.handleClick)}>Click Me</MyButton>;
  }
}

pass arguments to bound function

  // ...
  handleClick(index) {
    alert(this.message + ' (index: ' + index + ')');
  }

  render() {
    return (
      <div>
        {this.props.dataList.map((data, i) =>
          // across multiple renders, only one bound instance of
          // this.handleClick is created for each member of this.props.dataList
          <MyButton onClick={this.bind(this.handleClick, i)}>{data}</MyButton>
        )}
      </div>
    );
  }
}

install

With npm:

npm install @benwiley4000/bind-cache

Using a script tag:

<script src="https://unpkg.com/@benwiley4000/bind-cache"></script>
<script>
  console.log(bindCache); // should be a function
</script>

dependencies

This library is written in plain ES5 JavaScript so it will run in any browser you'll need to support, but you might need to polyfill Map and Symbol to support older browsers.

For compatibility, pass your substitutions for Map and Symbol in the optional second argument to bindCache:

this.bind = bindCache(this, { Map: MapPolyfill, Symbol: SymbolPolyfill });

For Map you can try the es6-map package.

For Symbol you can try the es6-symbol package.

However if you prefer something less heavy you can probably get away with the following:

function SymbolPolyfill() {
  // this should return something that you will NEVER pass
  // as an argument to bind - otherwise something could go wrong.
  return 1.513543544;
}

API

bindCache(objectInstance[, options])

allocates a new cache (optionally with Map and Symbol fallbacks) and returns a function bind which looks like:

bind(functionToBind[, ...callArguments])

Each call to bind(...) returns a function bound to objectInstance (and optionally to an additional list of call arguments).

The cache is never emptied and lasts as long as bind is referenced somewhere in the application (after which it will be garbage-collected).

why

In some cases a JavaScript class instance needs to pass one of its member methods around as a callback argument. Generally this method sound be bound to the class instance before being passed so that when invoked it will have access to the this context of that particular instance.

  render() {
    // each time render is called, we bind a copy of handleClick to the
    // instance and pass it to our MyButton child as an onClick prop
    return <MyButton onClick={this.handleClick.bind(this)}>Click Me</MyButton>;
  }

In the world of React components in particular (and perhaps others), it's typically desirable to bind the method only once and pass that bound method many times in the render method. Creating a new bound instance on each render can cause unnecessary re-renders in child components.

Typically this approach takes one of two forms:

  • Bind in the constructor
    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        // when the instance is created, we grab our methods
        // from the prototype and created bound copies on
        // the instance
        this.handleClick = this.handleClick.bind(this);
        this.handleHover = this.handleHover.bind(this);
        this.handleBlur = this.handleBlur.bind(this);
      }
        
      // ... method definitions
    
      render() {
        return <MyButton onClick={this.handleClick}>Click Me</MyButton>;
      }
    }
  • Use arrow function class "methods"
    class MyComponent extends React.Component {
      // when the instance is created, we create new
      // arrow function members bound to our instance
      handleClick = () => {
        // ...
      };
    
      handleHover = () => {
        // ...
      };
    
      handleBlur = () => {
        // ...
      };
    
      render() {
        return <MyButton onClick={this.handleClick}>Click Me</MyButton>;
      }
    }

Each of these approaches can be problematic:

  • Binding in the constructor introduces a lot of boilerplate that is annoying to maintain
  • Binding with arrow function members relies on the JavaScript class fields proposal which has not yet made it into the ECMAScript specification
  • Binding with arrow function members also means our methods are excluded from the class prototype, which can be a problem for testing, or if you are overriding a method in a derived class (rare in the React world, but certainly possible)
  • Each approach doesn't lend itself well to cases where functions need to be bound with additional call arguments. That case comes up when, for instance, an array of children needs to be rendered, each with a bound callback prop.

bindCache avoids all of the above problems.

comparisons to prior work

cached-bind by megazazik solves the same issues, but bind-cache has a few advantages:

  • Doesn't modify the object
  • No need for a key argument
  • Much simpler/smaller implementation (plain ES5)

However cached-bind doesn't require Map or Symbol, so it can work without polyfills in older browsers.

contributing

Please feel free to open a pull request with test cases or bug fixes.