Skip to content

Hook for creating callbacks that behave like class methods - function keeps the same reference during entire component lifecycle and always have access to 'fresh' variables from last render.

License

pie6k/use-method

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Useage

yarn add use-method

import { useMethod } from 'use-method';

function MyComponent() {
  const randomNumber = Math.random();

  // returns function that keeps the same reference during entire lifecycle of the component, while always using 'fresh' variables from last render
  const hiMethod = useMethod((name) => {
    // it'll always have `randomNumber` variable from the last render
    alert(`Hi, ${name} (${randomNumber})!`);
  });

  // hiMethod reference will remain the same on every render - if you'll pass it to other components like <MyComponent onEvent={hiMethod} /> it'll never re-render if it's memo or PureComponent
}

Introduction & Rationale

When hooks got introduced - it's became problematic to keep functions references the same on each render.

With classes it's not a problem. You just call this.handleClick which has the same reference on every render.

With functional components, you define such functions during rendering like

function SomeComponent() {
  function handleClick() {
    // handling click
  }

  // rendering
}

Without any optimization - handleClick would result in a brand new function on every render.

React useCallback hook is created to help solving this problem.

But even useCallback updates function reference when variables used as dependencies change.

Also - useCallback dependencies list tend to 'pollute' the code and might make it easy to introduce nasty bugs if you don't use proper linter.

use-method makes provided function behave like class method. It will have the same reference on every render, but it'll use values from last render.

Let's consider such example:

function PeopleToggler({ people, onToggle }) {
  const togglePerson = useMethod((person) => {
    // we want to always use `fresh` people and onToggle props here
    const peopleAfterToggle = oggleInArray(people, person);
    onToggle(peopleAfterToggle);
  });

  return <ToggleButton onToggle={togglePerson} />;
}

When togglePerson is called - it has access to fresh people and onToggle values.

At the same time, togglePerson reference remains constant.

The same component using useCallback could look like:

function PeopleToggler({ people, onToggle }) {
  const togglePerson = useCallback(
    (person) => {
      // we need fresh `people` and `onToggle` here
      const peopleAfterToggle = oggleInArray(people, person);
      onToggle(peopleAfterToggle);
    },
    [people, onToggle],
  );

  return <ToggleButton onToggle={togglePerson} />;
}

In this case, togglePerson will actually get a new reference every time props people or onToggle will update.

When to use it and when not to use it?

You can think about it in the same way as class method.

In class, if you'd have something like

<Button onPress={this.handlePress} />

It's fine, but if you'd have something like

class Table extends Component {
  cellLabel = 'Person';

  renderCell(item) {
    return (
      <div>
        Cell: {item.name} (type: {this.cellLabel})
      </div>
    );
  }

  render() {
    <div>
      {this.props.cells.map((cellData) => {
        return <Cell renderer={this.renderCell} key={someKey} />;
      })}
    </div>;
  }
}

It's not really safe, because if cellLabel will change - Cell will not know about it and as all it's props are the same - it'll not re-render.

Therefore you should use use-method mostly for events or something that dont impact rendering output.

Licence

MIT

About

Hook for creating callbacks that behave like class methods - function keeps the same reference during entire component lifecycle and always have access to 'fresh' variables from last render.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published