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

@arborjs/react

v0.0.1-alpha.93

Published

A fully typed, minimalistic proxy-based state tree library with very little boilerplate for React apps.

Downloads

243

Readme

Arbor React Binding

"Buy Me A Coffee"

Official React binding for @arborjs/store.

Installation

Via npm

npm install @arborjs/react

Or via yarn

yarn add @arborjs/react

Make sure you have @arborjs/store installed.

Usage

Similar to how you'd do in a Vanilla JS app, using Arbor in a React app can be done in 3 simple steps.

[!NOTE] Make sure you take a look at the documentation for @arborjs/store before using this biding. Also, take a moment to get familiar with some of the caveats of working with Arbor.

Take the following React app as an example:

export default function App() {
  return (
    <div>
      <Counter />
      <Actions />
    </div>
  )
}
  1. Create your Arbor store:
import { Arbor, useArbor } from "@arborjs/react"

const store = new Arbor({
  count: 0,
})
  1. Use the useArbor hook to connect React components to the store:
function Counter() {
  // This component will automatically re-render when the value of the counter changes
  const counter = useArbor(store)

  return <h1>Count: {counter.count}</h1>
}
  1. Mutate the store state using plain JS APIs:

[!NOTE] We don't need to useArbor here because this component does not need to re-render when the store changes.

function Actions() {
  return (
    <div>
      <button onClick={() => store.state.count--} value="Decrement">
        -1
      </button>
      <button onClick={() => store.state.count++} value="Increment">
        +1
      </button>
    </div>
  )
}

Stores can be as complex as you may need them to be, holding arrays, complex objects, or using classes to build a more complex data model for your application.

Optimal Re-Renders

Arbor implements a path tracking mechanism that allows for scoped store references. This is what powers the useArbor hook, enabling Arbor to determine exactly which React components must re-render when a specific part of the state is changed, avoiding unnecessary re-render by default.

Also, Arbor ensures that object and method references are stable, e.g. their memory reference is kept the same across re-renders unless the object changes, this means you can safely pass store objects via prop or use their methods as event handlers to components memoized with React's memo to prevent unnecessary re-render of component subtrees.

useArbor vs useState

You may choose to use useArbor instead of useState to manage the local state of your React components and leverage Arbor's reactive API, removing boilerplate while letting you focus on application logic.

// Application state held in an Arbor store
const store = new Arbor(new TodosApp())

function NewTodoForm() {
  // Use Arbor to manage the component's local state
  const form = useArbor({
    input: {
      value: "",
      onChange(e: ChangeEvent<HTMLInputElement>) {
        this.value = e.target.value
      },
    },
    onSubmit(e: FormEvent) {
      // Merge the local state back into the application store
      store.state.todos.push(new Todo(this.input.value))
      this.input.value = ""
    },
  })

  return (
    <form onSubmit={form.onSubmit}>
      <input {...form.input} />
      <button>Add</button>
    </form>
  )
}

By using Arbor to manage your component's local state, you can make that local state reactive, while being able to leverage all the simplicity of using JS standard constructs to interact with the state such as regular assignments, or other mutable APIs like Array#push.

Detached Fields vs useRef

Sometimes, it's useful to track values across component re-renders without triggering more re-renders as you change that value. Normally in React, you'd resort to useRef for that purpose.

Arbor allows you to decorate class fields with @detached to inform the store that the value should be detached from its state tree. This makes detached values non-reactive, e.g. changes to them will not trigger subscription notifications, in the context of React that translates to components not reacting to these changes, thus no re-rendering.

Imagine a hypothetical todos app where we need to track whether the priority of a todo has been changed for analytics purposes but that information does not have to be displayed anywhere on the UI, we can achieve that using @detached on the Todo type itself:

import { detached, proxiable } from "@arborjs/store"

@proxiable
class Todo {
  ...
  // Detached fields are "detached" from the store's state tree so changing
  // its value will not notify susbcribers.
  @detached priorityChanged = false
  ...
}

Changes to Todo#priorityChanged will not trigger mutation events in the store, preventing any components from re-rendering.

Learn By Example

We've put together a couple of code sandboxes with examples of how to use Arbor in a React app with code comments further explaining some of the concepts that you may find helpful.

Support This Project

"Buy Me A Coffee"

License

Arbor is MIT licensed.