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

signals-react-safe

v1.2.0

Published

A version of Preact Signals that integrates with React without touching React's internals. Allows Signals to be safely used with Next.js 13+'s App Router.

Downloads

2,827

Readme

signals-react-safe

Signals is a state management library from the Preact team. This is a safer alternative library.

The team provides a react compatibility library signals-react, but it comes with a very large downside: It alters React's internals. This is a big no-no for mainting compatibility with future versions of React, creating risk for your project. It also breaks compatibility with Next.js, which is a pretty good and popular React framework.

This library still lets you get the biggest benefit of Signals. When you render a signal directly within your JSX/TSX it creates a text node that updates when the signal updates, skipping the re-render of the component you render it within.

This library provides new hooks for reading the value of a signal in your React components. Instead of reading mySignal.value somewhere in your component, use useSignalValue(mySignal) instead.

IMHO, this is also helps readibility since it makes it more clear what can cause a component to re-render, and works better with hooks such as useEffect.

Live editable demo

Install

npm install signals-react-safe

Usage Example

mySignals.ts

import { signal } from 'signals-react-safe';

export const counter = signal(0);

Counter.tsx (this component does NOT re-render when the signal updates, which is more performant)

import { counter } from "./mySignals";

export function Counter() {
  return (
    <div>
      <div>Current Count: {counter}</div>
      <button onClick={() => counter.value++}>Add One</button>
    </div>
  );
}

MixedCounter.tsx (this component does re-render when the signal updates, which allows the value to be combined with non-signal values)

import { useState } from "react";
import { counter } from "./mySignals";

export function MixedCounter() {
  const counterValue = useSignalValue(counter);
  const [myCounter, setMyCounter] = useState(0);

  return (
    <div>
      <div>Summed: {counterValue + myCounter}</div>
      <button onClick={() => counter.value++}>Add One to signal counter</button>
      <button onClick={() => setMyCounter(myCounter + 1)}>
        Add One to useState counter
      </button>
    </div>
  );
}

API

This library provides a bunch of exported function:

  • Re-exports from the core Signals library: signal, computed, effect.
  • Copy/pasted hooks from @preact/signals-react: useSignal, useComputed, useSignalEffect.
  • New hooks unique to this library: useSignalValue, useSignalAndValue, useComputedValue.

useSignalValue(signal)

Takes as input an existing signal, typically imported into your module from elsewhere in your app. If you want your component to create its own signal, use useSignal instead.

It returns the value stored in the signal. When the signal's value changes, this hook will trigger a component re-render and return the new value.

Use this hook when you need to access the value stored in the signal, e.g. triggering a useEffect, or combining with non-signal values.

If you want to combine the value with other signal values, consider using useComputed or useComputedValue to be more performant.

Example:

import {count} from '../signals';
function Count() {
  const countValue = useSignalValue(count);
  useEffect(() => {
    localStorage['count'] = `#{countValue}`;
  }, [countValue]);
  return <div>{count} <button onClick={() => count.value++}>Add one</button></div>
}

useSignalAndValue

Creates a signal and returns it, along with its value. Triggers a component re-render in order to return the latest value. Use this to replace useSignal if you need to read the value of a component's signal within the component.

It returns an array with two elements:

  1. The signal.
  2. Its value.

Example:

function MyCounter() {
  const [count, countValue] = useSignalAndValue(0);
  useEffect(() => {
    localStorage['count'] = `#{countValue}`;
  }, [countValue]);
  return <div>{count} <button onClick={() => count.value++}>Add one</button></div>;
}

useComputedValue

Take a function as its parameter and returns a value. It's useful when that function uses multiple signals.

A new value will be generated if any of the referenced signals are updated, causing the component to re-render.

Example:

import {count} from '../signals';
function MyMultiplier() {
  const multiplier = useSignal(1);
  const multipliedValue = useComputedValue(() => multiplier.value * count.value);
  useEffect(() => {
    localStorage['multiplied'] = `#{multipliedValue}`;
  }, [countValue]);
  return <div>{multiplier} <button onClick={() => multiplier.value++}>Add one</button></div>;
}

Performance

The new hooks that directly return values will trigger re-renders of the component. This would also happen if you read a signal's value inside a component when using @preact/signals-react. If you want to avoid that re-render, place your signal directly in your JSX.

Author

Created by Jon Abrams (2023)

Attributions

Contains code from Preact Signals

Idea inspired by satoshi-cyber's suggestion.