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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@figliolia/preact-galena

v2.0.1

Published

Preact Bindings for the Galena state management library

Readme

Preact Galena

Preact Bindings for Galena! Using galena with preact is simple thanks to a set of factories for generating HOC's and hooks from your application state.

Installation

npm i -S @figliolia/galena @figliolia/preact-galena
# or
yarn add @figliolia/galena @figliolia/preact-galena

Getting Started

There are two primary API's developers can use for reading and mutating Galena State from Preact Components - hooks and HOC's! To get started, let's initialize some state and generate some hooks for accessing it in Preact:

Connecting Components to State Using Preact Hooks

The first part of this example, you're likely already familiar with. Let's set up a basic Galena instance at a attach a unit of State to it.

// AppState.ts;
import { Galena, State } from "@figliolia/galena";
import { createUseState, createUseMutation } from "@figliolia/preact-galena";

export const AppState = new Galena({
  navigation: new State({
    route: "/",
    userID: "123",
    permittedRoutes: "**/*",
  })
});

// Next, let's create some hooks for our components!

// Returns a hook for selecting values and updating values from your Navigation state
export const useNavigation = createUseState(AppState.get("navigation"));

createUseState()

createUseState() will accept any unit of State as a parameter and return a Preact Hook for selecting/mutating values from your state. Using the hook returned from createUseState(), you can read or compute from any value(s) in your application state and your component will re-render any time that value changes:

// Navigation.tsx
import { useNavigationState } from "./AppState";

const Navigation = () => {
  // Alternatively, you can use the hook generated from your
  // Navigation unit directly
  const [currentRoute, update] = useNavigationState(state => state.route);

  return (
    <nav>
      <div>{currentRoute}</div>
      <Link to="/" text="Home" />
      <Link to="/about" text="About" />
      <Link to="/contact" text="Contact" />
    </nav>
  );
};

Connecting Components to State Using HOC's

This library also provides factories for generating HOC's from your Galena and State instances. Let's take a look at the example above, this time, using HOC's:

// AppState.ts;
import { Galena, State } from "@figliolia/galena";
import { connect } from "@figliolia/preact-galena";

export const AppState = new Galena({
  navigation: new State({
    route: "/",
    userID: "123",
    permittedRoutes: "**/*",
  }),
  user: new State({
    userID: "<id>",
    friends: ["<id-1>", "<id-2>"]
  })
});

// Next, let's create some HOC's!

export const connectNavigation = connect(AppState.get("navigation")); 
// An HOC for reading values directly from your Navigation state

export const connectUser = connect(AppState.get("user")); 
// An HOC for reading values directly from your User state

Using Your Generated HOC's

// Navigation.ts
import { connectAppState, connectNavigation } from "./AppState";

const Navigation = ({ route }: { route: string }) => {
  return (
    <nav>
      <div>{route}</div>
      <Link to="/" />
      <Link to="/about" />
      <Link to="/contact" />
    </nav>
  );
}

// Using your Navigation HOC
export default connectNavigation({ route } => ({
  route,
  // ...any other properties you wish to return
}))(Navigation);

Advanced Connections

The HOC pattern can be cumbersome when binding multiple pieces of state to a Preact component. Galena solves this with the connectMulti() HOC generator.

import { State } from "@figliolia/galena";
import { connectMulti, type ReactiveStates } from "@figliolia/preact-galena";

// Let's create some basic state instances to start
const ListItems = new State([1, 2, 3, 4]);
const UserData = new State({ id: 1, name: "Bob Smith" });

// Instead of creating an HOC for each unit, we can use our `connectMulti()` factory to generate a single HOC that'll respond to both units of state
const ListAndUserConnection = connectMulti(ListItems, UserData);
// The ReactiveStates will generate typed selector parameters
// for your selector functions
export type ConnectionArgs = ReactiveStates<
  typeof ListAndUserConnection
>;

The ListAndUserConnection HOC can wrap any component you wish using the following pattern

// Let's grab the ListAndUserConnection from the code above
import {
  type ConnectionArgs,
  ListAndUserConnection,
} from "./ListAndUserConnection";

class MyComponent extends Component<{ list: number[]; name: string }> {
  override render() {
    const { name, list } = this.props;
    return (
      <div>
        <div>User Name: {name}</div>
        <ol>
          {list.map(el => (
            <li key={el}>{el}</li>
          ))}
        </ol>
      </div>
    );
  }
}

// Export your connected component!
export default ListAndUserConnection((
  [list, user]: ConnectionArgs, 
  ownProps: any
) => ({
  list,
  name: userData.name
}))(MyComponent);

As a result, we have a single wrapping HOC for MyComponent instead of multiple!

Stateful Actions that can be used inside and outside of Preact!

For maximum code-reuse, you may choose to compose generic actions for your state instances. This architectural pattern can create a more Redux-like development experience - but without requiring you to manage any reducers.

// NavigationMutations.ts
import { NavigationState } from "./NavigationState";

export const transitionRoute = (nextRoute: string) => {
  NavigationState.update(state => ({
    ...state,
    route: nextRoute,
  }));
};

export const updateRoutePermissions = (permissions: string) => {
  NavigationState.update(state => ({
    ...state,
    permittedRoutes: permissions
  }));
};

Using this pattern, you can simply create your state mutations then import them for use in your Preact Components and business logic:

import { transitionRoute } from "./NavigationMutations";

const Link = (
  { route, text }: { route: string; text: string }
) => {
  const navigate = e => {
    transitionRoute(e.target.href);
  };

  return (
    <a href={route} onClick={navigate}>
      {text}
    </a>
  );
};

In addition to creating redux-like actions, you can also create a more redux-like event emission pattern through Galena. For example, if you don't wish to interact with your state instances directly, you can try out something like this:

import { EventEmitter } from "@figliolia/event-emitter";
import { State } from "@figliolia/galena";

const MyStateStream = new EventEmitter<PayLoadTypes>();

// Extend the Default Galena State Instance to bind to actions
// you can name yourself!
export class MyState extends State<{ listItems: number[] }> {
  constructor() {
    super("My State", { listItems: [1, 2, 3, 4] });
    this.bindEvents();
  }

  private bindEvents() {
    MyStateStream.on("UPDATE_LIST", payload => {
      super.update(state => ({
        ...state,
        listItems: payload,
      }));
    });
    MyStateStream.on("REMOVE_LAST_ITEM", () => {
      super.update(state => ({
        ...state,
        listItems: listItems.slice(0, -1)
      }));
    });
  }
}

// Next, you can create some redux-like actions to dispatch
// updates to your state
export const updateList = (list: number[]) => {
  MyStateStream.emit("UPDATE_LIST", list);
};

export const removeLastItem = () => {
  MyStateStream.emit("REMOVE_LAST_ITEM", undefined);
};