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

react-signaler

v1.0.4

Published

Signals for react

Downloads

314

Readme

react-signaler

Based on: https://github.com/tc39/proposal-signals

!IMPORTANT! - This is not preact library like this @preact/signals-react. This library is made for react.

Usage

signal<Type>(value: Type): Signal<Type>

Signal with atomic value

import { signal } from 'react-signaler';

const num = signal(5);

const Component: FC = () => {
  return <h1>Num: {num()}</h1>;
};

Signal with object value

import { signal } from 'react-signaler';

const num = signal({ num: 5 });

const Component: FC = () => {
  return <h1>Num: {num((value) => value.num)}</h1>;
};

Get Signal value

import { signal } from 'react-signaler';

const num = signal({ num: 5 });
console.log(num.get()); // { num: 5 }
console.log(num.get((value) => value.num)); // 5

Set Signal value

import { signal } from 'react-signaler';

const num = signal({ num: 5 });
num.set({ num: 10 }); // { num: 10 }

Update Signal value

import { signal } from 'react-signaler';

const num = signal({ num: 5 });
num.update((value) => ({ ...value, num: 10 })); // { num: 10 }

Mutate Signal value

import { signal } from 'react-signaler';

const num = signal({ num: 5 });
num.mutate((value) => (value.num = 10)); // { num: 10 }

Use Signal value in react component

import { signal } from 'react-signaler';

const text = signal('');

const Component: FC = () => {
  return (
    <div>
      <h1>text: {text()}</h1>
      {text((value) => (
        <input value={value} onChange={(ev) => text.set(ev.target.value)} />
      ))}
    </div>
  );
};

useSignal() Create Signal in react component

import { useSignal } from 'react-signaler';

const Component: FC = () => {
  const { signal } = useSignal();
  const num = signal('unique-signal-key', () => 5);

  return <h1>Num: {num()}</h1>;
};

computed<Type>(compute: ()=>Type, watch?: (Signal | ReadonlySignal)[]): ReadonlySignal<Type>

watch?: (Signal | ReadonlySignal)[] optional argument.In some cases signals are not read in computed but depend on some signals. Watch array is useful for this cases.

Computed values are memoized but, they are always recomputed when the related signals are changed.

Create Computed

import { signal, computed } from 'react-signaler';

const name = signal('Peter');
const upperCaseName = computed(() => name.get().toUpperCase());

const Component: FC = () => {
  return <h1>name: {upperCaseName()}</h1>;
};

Create Computed object value

import { signal, computed } from 'react-signaler';

const name = signal('Peter');
const transformedName = computed(() => ({
  upperCase: name.get().toUpperCase(),
  lowerCase: name.get().toLowerCase(),
}));

const Component: FC = () => {
  return <h1>name: {transformedName((value) => value.lowerCase)}</h1>;
};

Read Computed value

import { signal, computed } from 'react-signaler';

const name = signal('Peter');
const transformedName = computed(() => ({
  upperCase: name.get().toUpperCase(),
  lowerCase: name.get().toLowerCase(),
}));

console.log(transformedName.get()); // { upperCase: "PETER", lowerCase: "peter" }
console.log(transformedName.get((value) => value.upperCase)); // PETER

useComputed() Create Computed in react component

import { useSignal, useComputed } from 'react-signaler';

const Component: FC = () => {
  const { signal } = useSignal();
  const { computed } = useComputed();

  const name = signal('name', () => 'Peter');
  const upperCaseName = computed('upperCaseName', () =>
    name.get().toUpperCase(),
  );

  return <h1>name: {upperCaseName()}</h1>;
};

effect(handler: ()=>void, watch?: (Signal | ReadonlySignal)[]): Dispose

watch?: (Signal | ReadonlySignal)[] optional argument.In some cases signals are not read in effect but depend on some signals. Watch array is useful for this cases.

Effects always run once immediately after created.

Effects always run lazy after each related signals are changed.

Crate effect

import { signal, effect } from 'react-signaler';

const name = signal('Peter');

const dispose = effect(() => {
  console.log(name.get());
});

// first console output: Peter

name.set('Erik');

// console output from lazy call: Erik

Dispose effect

Effects are disposables with dispose(...(Signal | ReadonlySignal)[]): void function.Example: dispose();

If the effect is related to multiple signals, there is a possibility to dispose one or more signals.Important if some of the related signals are disposed from the effect but the effect triggered then the disposed signals automatically are subscribing again.Example: dispose(nameSignal, ageSignal);

useSignalEffect() Create Effect in react component

import { useSignal, useComputed, useSignalEffect } from 'react-signaler';

const Component: FC = () => {
  const { signal } = useSignal();
  const { computed } = useComputed();
  const { effect } = useSignalEffect();

  const name = signal('name', () => 'Peter');
  const upperCaseName = computed('upperCaseName', () =>
    name.get().toUpperCase(),
  );

  const dispose = effect('log-user-name', () => {
    console.log(upperCaseName.get());
  });

  return <h1>name: {upperCaseName()}</h1>;
};

lazyEffect(handler: ()=>void, watch: (Signal | ReadonlySignal)[]): Dispose

Lazy effect almost the same as effect.

Lazy effect only runs after each related signals are changed.

Lazy effect watch: (Signal | ReadonlySignal)[] argument is required.

Create Lazy Effect

import { signal, lazyEffect } from 'react-signaler';

const name = signal('Peter');

const dispose = lazyEffect(() => {
  console.log(name.get());
}, [name]);

name.set('Erik');

// first console output from lazy call: Erik

Create Lazy Effect inside react component

import { useSignal, useComputed, useSignalLazyEffect } from 'react-signaler';

const Component: FC = () => {
  const { signal } = useSignal();
  const { computed } = useComputed();
  const { lazyEffect } = useSignalLazyEffect();

  const name = signal('name', () => 'Peter');
  const upperCaseName = computed('upperCaseName', () =>
    name.get().toUpperCase(),
  );

  const dispose = lazyEffect(
    'log-user-name',
    () => {
      console.log(upperCaseName.get());
    },
    [upperCaseName],
  );

  return <h1>name: {upperCaseName()}</h1>;
};

Features

batch<R>(cb: () => R): R

Batch can avoid unnecessary update steps.

import { signal, effect, batch } from 'react-signaler';

const count = signal(0);

const dispose = effect(() => {
  console.log(count.get());
});

// first console output: 0

count.set(1);
count.set(2);
count.set(3);

// console output: 1
// console output: 2
// console output: 3

batch(() => {
  count.set(1);
  count.set(2);
  count.set(3);
});

// after batch console output: 3

untrack<R>(signal: Signal<R>): Runtrack<R>(signal: ReadonlySignal<R>): Runtrack<R>(cb: () => R): R

Untrack can avoid any subscribes.

import { signal, effect } from 'react-signaler';
import { thisFunctionReadOtherSignals } from 'somewhere';

const name = signal('');

const dispose = effect(() => {
  const name = fetchURL.get();
  untrack(() => {
    thisFunctionReadOtherSignals(name);
  });
});

name.set('Peter');

Used built-in javascript features