Skip to content
This repository has been archived by the owner on Jun 6, 2019. It is now read-only.

Simple hook to provide instance variables for stateless components.

License

Notifications You must be signed in to change notification settings

jackgeek/react-instance-hook

Repository files navigation

react-instance-hook

Build Status

A React Hook that provides a simple way to avoid out-of-date state values in memoized functions

Provides an object that can be used to store instance variables.

Usage

import useInstance from "react-instance-hook";

// ...
const [instance: Object, updateInstance: Function] = useInstance(initialInstanceState: Object);
// OR
const [instance: Object, updateInstance: Function] = useInstance(() => Object);

Why use this?

When using useMemo or useCallback the state values from useState are captured and therefore could be out of date.

For example

function MyComponent() {
  const [value, setValue] = useState(2);
  const double = useCallback(() => setValue(value * 2), []);
  return <Widget value={value} setValue={setValue} double={double} />;
}

The above memoizes the double callback using the useCallback hook to avoid causing the Widget to re-render every time MyComponent rerenders. But there is a bug in this code! When Widget calls double it will always return 4. This is because the initial value of 2 is captured in the closure passed to useCallback.

To workaround this problem we can create an instance object and as the object reference is captured the problem goes away:

function MyComponent() {
  const [{ instance }] = useState({ instance: { value: 2 } });
  const double = useCallback(() => (instance.value = instance.value * 2), []);
  return <Widget value={instance.value} setValue={setValue} double={double} />;
}

But wait! This also has a bug. The widget does not receive the doubled value. This is because no state has changed and so the component does not rerender.
useInstance provides a function you can call to force an update to occur.

function MyComponent() {
  const [instance, update] = useInstance({ value: 2 });
  const double = useCallback(() => update((instance.value *= 2)), []);
  return <Widget value={instance.value} setValue={setValue} double={double} />;
}

Note that the update call does nothing with the value passed to it. The following would be equivalent:

const double = useCallback(() => {
  instance.value *= 2;
  update();
}, []);

Caution

I have been playing with hooks in anger only a short time. This could well be an anti-pattern! Use your judgement and please do read the source code in index.js to understand how it works.

About

Simple hook to provide instance variables for stateless components.

Resources

License

Stars

Watchers

Forks

Packages

No packages published