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-tree-reconciler

v1.2.0

Published

Simpler API for React reconcilers

Downloads

4

Readme

npm version downloads build status coverage status Language grade: JavaScript Node.JS version

react-tree-reconciler is a simpler API of the React reconciler. It can be seen as a React reconciler factory. It makes assumptions, and has specializations which makes it unsuitable for very complex applications. In many cases though, this package works well and is a whole lot simpler than building a reconciler from scratch.

API

The package contains three main pieces;

  • A way to create custom "native" components (think; a, div, span if this was for the web)
  • A connection between such a "native" component and a custom class (where an instance of the component becomes an instance of the class)
  • Bootstrapping a React tree lifecycle

Native components

Create native components using makeComponent. This takes a props type and a textual name, and returns the component in an object with that same name. This API decision has technical reasons which hides complexity, and is easy to use right, and hard to misuse. It's easy to create a file containing the components and exporting them.

Example;

// components.ts
import { makeComponent } from 'react-tree-reconciler'

export interface FooProps
{
    title: string;
    description?: string;
}
export const { Foo } = makeComponent< FooProps >( )( 'Foo' );

export interface BarProps { /* ... */ }
export const { Bar } = makeComponent< BarProps >( )( 'Bar' );

This component can now be used as:

import { Foo } from './components.ts'

function ManyFoos( )
{
    // Hooks are of course supported in user-created components
    // since a true React is used with the corresponding lifecycles.
    const [ desc, setDesc ] = useState( 'second foo' );

    return <>
        <Foo title="foo 1" />
        <Foo title="foo 2" description={ desc } />
    </>
}

To create a component which shouldn't be able to have children, use makeVoidComponent.

You can import the frontend-parts (component construction logic) from react-tree-reconciler/components to not get the potential dependency issues when importing the whole package.

Connecting a React component with a class

Tree classes

Each node in the react tree will create a corresponding instance of ReactTreeItem which is either a ReactTreeText or a ReactTreeNode.

The ReactTreeText is a class which only has the useful text property being the string corresponding to the free text. It also has a property type being "text".

The ReactTreeNode< Props, Context > has the type property set to "node", and then has the following properties:

  • elementType: stringThis is the React name of the component, as provided to makeComponent()
  • props: PropsRaw React props
  • context: ContextOptional context

It also has the following no-op functions which can be overridden:

  • onChildrenChanged( )Called when the children change (added, removed, replaced)
  • onFinalizeChildren( )Called the first time the children are provided
  • onPropsChanged( )Called when the props have changed

You can provide a custom constructor function which returns a subclassed instance of ReactTreeNode, so that you can store arbitrary other data on the nodes, and if necessary, use data in the Context.

Example;

class MyFooImpl extends ReactTreeNode< FooProps, Context >
{
	static make( type: string, props: FooProps, context: Context )
	{
		return new MyFooImpl( type, props, context );
	}

	public getMagicTitle( )
	{
		return "magic " + this.props.title;
	}
}

You can the provide MyFooImpl.make as the constructor to instances of the React component Foo as defined above, see Connection below.

Context

When creating a reconciler and a tree of components, react-tree-reconciler allows you to provide a custom "context". A type safe piece of data you control entirely yourself. This can contain necessary information about the tree as a whole and connections to the rest of your app.

Connection

Use setupElements to connect React components to your custom classes:

import { Foo, Bar } from './components'

// Context can be null if you don't need it, or any data you like
type Context = { foo: number };
const context: Context = { foo: 42 };

class MyFooImpl extends ReactTreeNode< ... > { ... }

const elementSetup = setupElements( {
    elements: [
        [ Foo, MyFooImpl.make ],
        [ Bar, MyBarImpl.make ],
    ],
    context,
} );

Bootstrapping a React tree lifecycle

Use setupReconciler and the returned render to bootstrap the React tree.

Note that you can have multiple React trees (and their corresonding lifecycles) concurrently in your app!

const { rootContainer, render } = setupReconciler(
    <ManyFoos />,
    { elementSetup }
);

render( );

The rootContainer is an object similar to your subclassed tree nodes, and has a function getChildren( ) which can be used to iterate the the children of this root. From there on, you can iterate by accessing the children property on each sub-node, as long as it's a subclas of ReactTreeNode and not ReactTreeText.

You can provide a custom root container, as long as it extends ReactTreeNode and implements ContainerNode:

interface ContainerNode
{
    doClear( ): void;
    onPrepareForCommit?( ): void;
    onResetAfterCommit?( ): void;
}

doClear should probably call this.clear( ); to clear the entire tree.

The other functions are optional to implement, and are called before and after the tree has been mutaded by the reconciler. These are often not necessary to implement.

Finally, add an instance of this container class called rootContainer to the second options object in the call to setupReconciler and that will be used as the root container, rather than an automatically created one.

Debug logging

If you want to see debug logs from the reconciler, to understand what's going on (NOTE; it's going to be massive amounts of logs), you can provide yet another option in the second options object to setupReconciler - a function called debugLogReconciliation on the form ( message: string, ...args: any ) => void