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

@wonderlandlabs/freactal-connect

v1.0.9

Published

This is a library for connecting Freactal StoreEngines to React components.

Downloads

5

Readme

This is a library for connecting Freactal StoreEngines to React components.

It uses the Freactal Store Engine-- @wonderlandlabs/freactal-engine.

API

The Freactal connector uses several methods to communicate state into components:

provideState({state, initialize?, actions}, Target?, inject?)

provideState creates a new engine and injects it into context, allowing for it to be consumed by downstream readers. This is done "under the hood" by putting a value into a React Context.

  • The first argument is the engines' parameters.
    • state is an object that will be the store's starting values.
    • initialize is a function that will set the stores' values before any action is executed. It is an asynchronous function, so you can poll APIs or do any other promise based activity here. It is optional.
    • actions is an object with methods that take in a context (the engine) and optional arguments, and returns a new state.
  • The second argument is an optional component to inject state for.
  • The third argument is a boolean - indicates whether to directly inject the engine into the target.

Example:


const Root = ({state, actions, children}) => {
    return (
      <div>
      <h1>I Provide State!</h1>
      <div>
        a = {state.a}
        <button onClick={actions.addOneToA()}>Add One To A</button>
      </div>
      {children}
      </div>
    )
}

const engine = new StoreEngine(
    {a: 1, b: 2, },
    {
        addOneToA: ({state}) => {
            return Object.assign({}, state, {a: state.a + 1});
        },
        addValueToB: ({state}, n) => {
            return Object.assign({}, state, {b: state.b + n});
          }
    });

const wrapperFunction = provideState({
    state: {a: 1, b: 2},
    actions: {
      incA: ({state}) => Object.assign({}, state, {a: state.a + 1})
    }
});

/**
 * method one: create a wrapper function
 */

const WrappedRoot = wrapperFunction(Root);

/**
 * method two: wrap directly. Note - this will NOT work if Root USES state.
 * 
 */

const WrappedRoot = provideEngine(engine)( Root);

/**
 * --- but this WILL work.
 * 
 */

const WrappedRoot = provideEngine(engine)(injectState(Root));

injectState(Target, customPropInjector?)

makes freactal state and actions available to a wrapped version of Target.

By default, the properties state, actions, and (sigh) effects (an alias to actions) are provided, with any properties passed to the wrapped view.

However you can also decide to provide a second function that takes in the outer component and returns the properties injected to the child view. So if you want to take a subset of values of the state, or compute (synchronous) derived values based on state, you can do so with the third property. (no need to include children as a property - its managed elsewhere).

So, the two examples will render identically, if provideState from above is used at a higher level:


const BasicStatedInstance = injectState(({state, actions}) => {
    return (
      <div>
          a = {state.a}, b = {state.b} 
        <div>
          <button onClick={actions.incrementA}>Increment A</button>
          <button onClick={() => actions.addValueToB(5)}>Add 5 to B</button>
        </div>
      </div>
    );
});

or if you want to pull state into props directly,


const BasicStatedInstance = injectState(({incrementA, addValueToB, a, b}) => {
    return (
      <div>
          a = {a}, b = {b} 
        <div>
          <button onClick={incrementA}>Increment A</button>
          <button onClick={() => addValueToB(5)}>Add 5 to B</button>
        </div>
      </div>
    );
},
 (props, context) => {
  return Object.assign({}, props, context.actions, {a: context.state.a, b: context.state.b});
});

provideEngine(engine, target?, inject?)

provideEngine is an advanced variation of provideState above. instead of creating a store engine internally, provideEngine allows you to define the engine externally.

The engine should connect any stores that follow the following signature:

  • state: a property that has a value that changes when actions are called
  • actions: an object whose properties are functions that change the state
  • subscribe: a method that follows the RxJS subscription pattern(onUpdate, onError, onTerminate)

As with provideState, the target can be defined and if desired, injected with state.


Example:


class Root extends React.PureComponent {
  
  render() {
    return (
      <div>
      <h1>I Provide State!</h1>
      <div>a = {this.props.state.a}</div>
      {this.props.children}
      </div>
    )
  }
  
}

const engine = new StoreEngine({a: 1, b: 2, }, {inc: ({state}) => {
  return Object.assign({}, {a: state.a + 1});
}});

/**
 * method one: create a wrapper function
 */

const wrapperFunction = provideEngine(engine);

const WrappedRoot = wrapperFunction(Root);

/**
 * method two: wrap directly
 */

const WrappedRoot = provideEngine(engine)(Root);

Some Advanced Notes

how do we ensure that state values are unique when provided multiple times?

The state argument is ran through lodash.cloneDeep (don't worry we don't pull in all of lodash). however if there are complex/OOP arguments where references are important they should be provided with the initialize method.

When you call nested actions how do you ensure that context.state is up to date?

Context is the engine instance itself. So the state property of it is updated after the resolution of any actions. to be safe ensure that you await any actions or use call.then(...) notation to resolve the actions before polling state again.

Can I use Freactal 3 with pre-16.x React?

Freactal 3 relies on 16.3 Contexts. We will provide a ...14.x friendly option soon that will accept legacy Context support.

Can I use Freactal 3 with "not React"?

Freactal itself uses React 16.3 as a peer dependency. However it wraps functions and anything else you feed to it so in theory, you can use it around other systems as long as you provide a React library for the inner workings of Freactal.

Does Freactal work with server side rendering?

If you provide starting values for the state it should render with SSR. (hasn't been tested yet)