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-solid-signals

v1.1.6

Published

Using signals in react to boost performance

Downloads

12

Readme

react-solid-signals

Using Signals in react to boost performance.

Problem with react useState

export default function App() {
  const [count, setCounter] = useState(0);

  return (
    <div className="App">
      <h1>Hello useState </h1>
      <h3>Counter is {count}</h3>
      <button
        onClick={() => {
          setCounter((prev) => prev + 1);
        }}
      >
        Increment Counter
      </button>
      <SomeHeavyComponent />
    </div>
  );
}

The component SomeHeavyComponent is going to get re-rendered whenenver the count is changed. This is a big problem, that we solve on a daily basis when we consider performance as our key metric. Careful state management with many clever tricks will solve many such performance problems. But the question is what if we can avoid this problem altogether. What if we can avoid this problem without using a different JS framework like Solid JS and still uisng the rich ecosystem of React JS.

Try it on codesanbox https://codesandbox.io/s/compassionate-water-jkzfib?file=/src/App.tsx

useSignal

Usage

import { useSignal }  from 'react-solid-signals';

const SomeComponent = ()=>{
  const [counter, setCounter] = useSignal(0);
  
  return <>
    <div>
      Counter is {counter.jsx()}
      <br></br>
      <button onClick={()=>{
        setCounter((prev)=>prev+1)
      }}>Increment Counter</button>
    </div>
    //otherComponents 
  </>
}

useSignal returns an array, with first element as an object, which contains 2 signalGetters { value, jsx }. Whenever you want to access the signal value inside a jsx, use counter.jsx() otherwise use counter.value().

The second element of the returned array is a setter which is identical to the setState React dispatch setter we use with useState.

Now even when the counter value is changed continously when the user clicks on the button, none of components in the jsx tree is re-rendered, only the part {counter.jsx} is re-rendered.

useEffectSignal

Standard React useEffect wont work with signals,to perform side effects whenever signals change, we need useEffectSignal. Usage

import { useEffectSignal }  from 'react-solid-signals';

useEffectSignal(()=>{
  //this function will be executed whenever its dependency is changed
  console.log('counter',counter.value())
},[counter])

useEffectSignal takes a function as the first argument and a dependency array as the second argument. Dependency array must be an array of signals only.

useMemoSignal

Usage

import { useMemoSignal }  from 'react-solid-signals';

const memosizedData = useMemoSignal(()=>{

  console.log('counter',counter.value())
  return counter.value() * 4;
},[counter])

memosizedData is also a signal and have the same two getters { jsx, value }. The memosizedData signal will be updated only when the counter signal is changed. The hook also accepts a 3rd argument as defaultValue, if provided then the defaultValue will be used to initilize the signal.

Show

In React while using state we use conditional rendering like the below

const SomeComponent = () => {
  const [counter, setCounter] = useState(0)
  
  return <div>
    {counter ===2 ? 
      <div>Counter is 2</div>:
      <div> Counter is not 2</div>
      }
  </div>
}

This type of conditional rendering will not work with signals. To achieve the same functionality using signals, we must use Show component provided by the library as follows:

import { Show, useSignal } from 'react-solid-signals';

const SomeComponent = () => {
  const [counter, setCounter] = useSignal(0)
  
  return <div>
    <Show jsxCallback={()=>{
      return count.value() === 2 ? 'Counter is 2' : 'Counter is not 2';
    }} deps={[counter]}/>
  </div>
}

A jsxCallback is a function which returns an JSX element and deps is an array of signals. JSX callback is again re-evaluated whenever the signals given in the dependency array is changed

Use signals in redux

You can use react-redux useSelector hook, but it will again cause re-render of the components. Create the below redux hook to select signals from redux store. You must provide your store instance in signalStoreInitializer.

import { signalStoreInitializer } from "react-solid-signals";
import { store } from "./store";

export const useSignalSelector = signalStoreInitializer(store);

If you are using typescript then use the below hook.

import { store } from "./store";
import {
  TypedUseSelectorSignalHook,
  signalStoreInitializer,
} from "react-solid-signals";

export type RootState = ReturnType<typeof store.getState>

export const useSignalAppSelector: TypedUseSelectorSignalHook<RootState> =
  signalStoreInitializer(store);

Usage of useSignalAppSelector/ useSignalSelector in a component

const SomeComponent = ()=>{
  const count = useSignalAppSelector((state)=>state.main.count,0)

  return <>
    {count.jx()}
  </>
}

Currently you must provide a default value in the hook as the second parameter. This default value will be used unless the signal is not updated with the correct value from the store.

There are no limitations of the getter singal.value(), all the methods, properties is possible on the data is also supported by this getter.

Current Limitations of signal.jsx() getter.

  1. Join operation on signal.jsx() is not supported (if the data is of type Array)
  2. Filter operation on signal.jsx() is not supported
  3. Nested arrays are not suppported
  4. null/undefined not supported

I am constantly working on this limitations. Please feel free to create a PR or an issue if needed.