0.1.25 • Published 3 years ago

usestable v0.1.25

Weekly downloads
-
License
ISC
Repository
github
Last release
3 years ago

useStable

A React hook to create stable component/object

Installation

with NPM

npm i usestable --save

with YARN

yarn add usestable

Motivation

Inspired by useEvent RFC

Recipes

Stable identity callback

with useEvent

import { useEvent } from "react";

function Chat() {
  const [text, setText] = useState("");

  const onClick = useEvent(() => {
    sendMessage(text);
  });

  return <SendButton onClick={onClick} />;
}

with useStable

import { useStable } from "react";

function Chat() {
  const [text, setText] = useState("");
  const stable = useStable({
    onClick: () => {
      sendMessage(text);
    },
  });

  return <SendButton onClick={stable.onClick} />;
}

Stable component

For above examples, you must wrap your SendButton with memo(). Need to useEvent every time and easy to forget. usestable provide stable() HOC to create a stable component on the fly

import { stable } from "usestable";

const SendButton = stable((props) => {
  // implementation
});

// you also wrap 3rd-party components
import { Button } from "antd";

// even with specified props only. by default, all props will be stable
const SendButton = stable(Button, { props: ["onClick"] });

There you go, no need to wrap any event callbacks. You also free with inline callbacks

function Chat({ rooms }) {
  const [text, setText] = useState("");

  return rooms.map((room) => (
    <SendButton
      // if you wrap SendButton with stable(), you dont not worry this
      onClick={
        () => sendMessage(room, text)
        // 🙁 Can't wrap it with useEvent
      }
    />
  ));
}

Geting fresh values in callbacks

Sometimes, useEvent fails with async callback

with useEvent

const contextVariable = useContext(SomeContext);
const callback = useEvent(async () => {
  // the contextVariable is fresh now
  console.log(contextVariable);
  await callAsyncMethod();
  // but it is outdated now
  console.log(contextVariable);
});

You must use more useEvent hook to handle above case

const contextVariable = useContext(SomeContext);
const onDone = useEvent(() => {
  // do something with contextVariable
});
const callback = useEvent(async () => {
  // the contextVariable is fresh now
  console.log(contextVariable);
  await callAsyncMethod();
  onDone();
});

with useStable #1

import { useStable } from "usestable";

const contextVariable = useContext(SomeContext);
// create stable object to hold contextVariable
const stable = useStable({ contextVariable });
const callback = useCallback(async () => {
  // the contextVariable is fresh now
  console.log(stable.contextVariable);
  await callAsyncMethod();
  // and it is still fresh now and after. Easy ?
  console.log(stable.contextVariable);
}, [stable]);

with useStable #2

import { useStable } from "usestable";

const contextVariable = useContext(SomeContext);
// create stable object to hold contextVariable
const { callback } = useStable({
  // add contexture variables
  contextVariable,
  // define async callback
  async callback() {
    // using this object to access stable props
    // the contextVariable is fresh now
    console.log(this.contextVariable);
    await callAsyncMethod();
    // and it is still fresh now and after. Easy ?
    console.log(this.contextVariable);
  },
});

Using stable object with other React hooks

You can use stable object with any React's hooks

const stable = useStable({
  some,
  stable,
  variables,
  here,
  dateValue, // useStable will not update date values if its timestamp does not change
  stableCallback() {},
});

const flexibleCallback = useCallback(() => {
  console.log(unstableVar);
  console.log(stable.variables);
}, [stable, unstableVar /* add dependencies to control callback re-create */]);

useEffect(() => {
  socket.on("connected", () => {
    console.log(stable.some);
    console.log(stable.variables);
  });
}, [stable /* add more dependencies ad you need */]);

Conditional callbacks

Sometimes React memo and useEvent fail with conditional callbacks

function Chat({ onOdd, onEven }) {
  const [text, setText] = useState("");

  return <SendButton onClick={text.length % 2 ? onEven : onOdd} />;
}

You must add more useEvent hook to handle conditional callbacks

function Chat({ onOdd, onEven }) {
  const [text, setText] = useState("");
  const onClick = useEvent(() => (text.length % 2 ? onEven() : onOdd()));

  return <SendButton onClick={onClick} />;
}

If SendButton already wrapped by stable() HOC, everything done without any effort

API reference

https://linq2js.github.io/usestable/

0.1.25

3 years ago

0.1.24

3 years ago

0.1.23

3 years ago

0.1.22

3 years ago

0.1.21

3 years ago

0.1.20

3 years ago

0.1.19

3 years ago

0.1.18

3 years ago

0.1.17

3 years ago

0.1.16

3 years ago

0.1.15

3 years ago

0.1.14

3 years ago

0.1.13

3 years ago

0.1.12

3 years ago

0.1.11

3 years ago

0.1.10

3 years ago

0.1.9

3 years ago

0.1.8

3 years ago

0.1.7

3 years ago

0.1.6

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago

0.0.7

3 years ago

0.0.6

3 years ago

0.0.5

3 years ago

0.0.4

3 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago