GithubHelp home page GithubHelp logo

formidablelabs / freactal Goto Github PK

View Code? Open in Web Editor NEW
1.7K 78.0 47.0 371 KB

Clean and robust state management for React and React-like libs.

License: MIT License

JavaScript 98.12% CSS 0.11% Shell 1.77%
react state-management state preact inferno

freactal's Introduction

fr(e)actal

CircleCI

freactal is a composable state management library for React.

The library grew from the idea that state should be just as flexible as your React code; the state containers you build with freactal are just components, and you can compose them however you'd like. In this way, it attempts to address the often exponential relationship between application size and complexity in growing projects.

Like Flux and React in general, freactal builds on the principle of unidirectional flow of data. However, it does so in a way that feels idiomatic to ES2015+ and doesn't get in your way.

When building an application, it can replace redux, MobX, reselect, redux-loop, redux-thunk, redux-saga, [fill-in-the-blank sub-app composition technique], and potentially recompose, depending on how you're using it.

Its design philosophy aligns closely with the Zen of Python:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.

Submitting Bugs

If you encounter an issue with freactal, please look to see if the issue has already been reported. If it has not, please open a new issue.

When submitting a bug report, make sure to include a repro. The best way to do this, is to fork the freactal-sketch sandbox, modify it so that the bug is observable, and include a link in your bug report.

Table of Contents

Guide

This guide is intended to get you familiar with the freactal way of doing things. If you're looking for something specific, take a look at the API Documentation. If you're just starting out with freactal, read on!

Containing state

Most state management solutions for React put all state in one place. freactal doesn't suffer from that constraint, but it is a good place to start. So let's see what that might look like.

import { provideState } from "freactal";

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 })
});

In the above example, we define a new state container type using provideState, and provide it an argument. You can think about the arguments passed to provideState as the schema for your state container; we'll get more familiar with the other possible arguments later in the guide.

The initialState function is invoked whenever the component that it is wrapping is instantiated. But so far, our state container is not wrapping anything, so let's expand our example a bit.

import React, { Component } from "react";
import { render } from "react-dom";

const Parent = ({ state }) => (
  <div>
    { `Our counter is at: ${state.counter}` }
  </div>
);

render(<Parent />, document.getElementById("root"));

That's a very basic React app. Let's see what it looks like to add some very basic state to that application.

import React, { Component } from "react";
import { render } from "react-dom";
import { provideState } from "freactal";

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 })
});

const Parent = wrapComponentWithState(({ state }) => (
  <div>
    { `Our counter is at: ${state.counter}` }
  </div>
));

render(<Parent />, document.getElementById("root"));

Alright, we're getting close. But we're missing one important piece: injectState.

Like provideState, injectState is a component wrapper. It links your application component with the state that it has access to.

It may not be readily apparent to you why injectState is necessary, so let's make it clear what each freactal function is doing. With provideState, you define a state template that can then be applied to any component. Once applied, that component will act as a "headquarters" for a piece of state and the effects that transform it (more on that later). If you had a reason, the same template could be applied to multiple components, and they'd each have their own state based on the template you defined.

But that only tracks state. It doesn't make that state accessible to the developer. That's what injectState is for.

In early versions of freactal, the state was directly accessible to the component that provideState wrapped. However, that meant that whenever a state change occurred, the entire tree would need to re-render. injectState intelligently tracks the pieces of state that you actually access, and a re-render only occurs when those pieces of state undergo a change.

Alright, so let's finalize our example with all the pieces in play.

import React, { Component } from "react";
import { render } from "react-dom";
import { provideState, injectState } from "freactal";

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 })
});

const Parent = wrapComponentWithState(injectState(({ state }) => (
  <div>
    { `Our counter is at: ${state.counter}` }
  </div>
)));

render(<Parent />, document.getElementById("root"));

That'll work just fine!

Accessing state from a child component

As was mentioned above, the provideState-wrapped component isn't really the one that provides access to state. That's injectState's job. So what would stop you from injecting state into a child component that isn't containing state itself? The answer is nothing!

Let's modify the example so that we're injecting state into a child component.

import React, { Component } from "react";
import { render } from "react-dom";
import { provideState, injectState } from "freactal";


const Child = injectState(({ state }) => (
  <div>
    { `Our counter is at: ${state.counter}` }
  </div>
));

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 })
});

const Parent = wrapComponentWithState(({ state }) => (
  <Child />
));


render(<Parent />, document.getElementById("root"));

Let's review what's going on here.

  1. Using provideState, we define a state-container template intended to store a single piece of state: the counter.
  2. That template is applied to the Parent component.
  3. When the Parent is rendered, we see that it references a Child component.
  4. That Child component is wrapped with injectState.
  5. Because Child is contained within the subtree where Parent is the root node, it has access to the Parent component's state.

We could insert another component at the end, and injectState into the GrandChild component, and it would work the same.

Transforming state

Alright, so we know how to setup state containers, give them an initial state, and consume that state from child components. But all of this is not very useful if state is never updated. That's where effects come in.

Effects are the one and only way to change freactal state in your application. These effects are defined as part of your state container template when calling provideState, and they can be invoked from anywhere that state has been injected (with injectState).

Let's take a look at that first part.

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 }),
  effects: {
    addOne: () => state => Object.assign({}, state, { counter: state.counter + 1 })
  }
});

You might be wondering why we have that extra () => right before state => in the addOne definition. That'll be explained in the next section - for now, let's look at all the other pieces.

In the above example, we've defined an effect that, when invoked, will update the counter in our state container by adding 1.

Since updating an element of state based on previous state (and potentially new information) is something you'll be doing often, freactal provides a shorthand to make this a bit more readable:

const wrapComponentWithState = provideState({
  initialState: () => ({ counter: 0 }),
  effects: {
    addOne: update(state => ({ counter: state.counter + 1 }))
  }
});

Now let's look at how you might trigger this effect:

const Child = injectState(({ state, effects }) => (
  <div>
    { `Our counter is at: ${state.counter}` }
    <button onClick={effects.addOne}>Add one</button>
  </div>
));

Wherever your <Child /> is in your application, the state and effects it references will be accessible, so long as the state container is somewhere further up in the tree.

Transforming state (cont.)

If you've used Redux, effects are roughly comparable to an action-reducer pair, with a couple of important differences.

The first of those differences relates to asychronicity. Under the hood, freactal relies heavily on Promises to schedule state updates. In fact, the following effects are all functionally equivalent:

addOne: () => state => Object.assign({}, state, { counter: state.counter + 1 })
/* vs */
addOne: () => Promise.resolve(state => Object.assign({}, state, { counter: state.counter + 1 }))
/* vs */
addOne: () => new Promise(resolve => resolve(state => Object.assign({}, state, { counter: state.counter + 1 })))

To put it explicitly, the value you provide for each key in your effects object is:

  1. A function that takes in some arguments (we'll cover those shortly) and returns...
  2. A promise that resolves to...
  3. A function that takes in state and returns...
  4. The updated state.

Step 2 can optionally be omitted, since freactal wraps these values in Promise.resolve.

For most developers, this pattern is probably the least familiar of those that freactal relies upon. But it allows for some powerful and expressive state transitions with basically no boilerplate.

For example, any number of things can occur between the time that an effect is invoked and the time that the state is updated. These "things" might include doing calculations, or talking to an API, or integrating with some other JS library.

So, you might define the following effect:

updatePosts: () => fetch("/api/posts")
  .then(result => result.json())
  .then(({ posts }) => state => Object.assign({}, state, { posts }))

In other words, any action that your application might take, that ultimately could result in a state change can be simply expressed as an effect. Not only that, but this pattern also allows for effects and UI components to be tested with clean separation.

And, perhaps most importantly, this pattern allows for intermediate state.

Intermediate state

So far, we haven't see any arguments to the first, outer-most function in our effect definitions. In simple scenarios, this outer-function may seem unnecessary, as in the illustration above.

But what about cases where you want state to be updated part-way through an operation? You could put all this logic in your UI code, and invoke effects from there multiple times. But that's not ideal for a number of reasons:

  1. A single effect might be invoked from multiple places in your application.
  2. The code that influences how state might be transformed is now living in multiple places.
  3. It is much harder to test.

Fundamentally, the problem is that this pattern violates the principle of separation of concerns.

So, what's the alternative?

Well, we've already defined an effect as a function that, when invoked, will resolve to another function that transforms state. Why couldn't we re-use this pattern to represent this "part-way" (or intermediate) state? The answer is: nothing is stopping us!

The first argument passed to an effect in the outer function is the same effects object that is exposed to components where state has been injected. And these effects can be invoked in the same way. Even more importantly, because effects always resolve to a Promise, we can wait for an intermediate state transition to complete before continuing with our original state transition.

That might be a lot to take in, so let's look at an example:

const wrapComponentWithState = provideState({
  initialState: () => ({
    posts: null,
    postsPending: false
  }),
  effects: {
    setPostsPending: update((state, postsPending) => ({ postsPending })),
    getPosts: effects => effects.setPostsPending(true)
      .then(() => fetch("/api/posts"))
      .then(result => result.json())
      .then(({ posts }) => effects.setPostsPending(false).then(() => posts))
      .then(posts => state => Object.assign({}, state, { posts }))
  }
});

There's a lot going on there, so let's go through it piece by piece.

  • The initial state is set with two keys, posts and postsPending.
    • posts will eventually contain an array of blog posts or something like that.
    • postsPending is a flag that, when true, indicates that we are currently fetching the posts.
  • Two effects are defined.
    • setPostsPending sets the postsPending flag to either true or false.
    • getPosts does a number of things:
      • It invokes setPostsPending, setting the pending flag to true.
      • It waits for the setPostsPending effect to complete before continuing.
      • It fetches some data from an API.
      • It parses that data into JSON.
      • It invokes setPostsPending with a value of false, and waits for it to complete.
      • It resolves to a function that updates the posts state value.

In the above example, setPostsPending has a synchronous-like behavior - it immediately resolves to a state update function. But it could just as easily do something asynchronous, like make an AJAX call or interact with the IndexedDB API.

And because all of this is just Promise composition, you can put together helper functions that give consistency to intermediate state updates. Here's an example:

const wrapWithPending = (pendingKey, cb) => effects  =>
  effects.setFlag(pendingKey, true)
    .then(cb)
    .then(value => effects.setFlag(pendingKey, false).then(() => value));

Which could be consumed like so:

const wrapComponentWithState = provideState({
  initialState: () => ({
    posts: null,
    postsPending: false
  }),
  effects: {
    setFlag: update((state, key, value) => ({ [key]: value })),
    getPosts: wrapWithPending("postsPending", () => fetch("/api/posts")
      .then(result => result.json())
      .then(({ posts }) => state => Object.assign({}, state, { posts }))
    )
  }
});

Effect arguments

But what if you want to update state with some value that you captured from the user? In Redux parlance: what about action payloads?

If you were looking closely, you may have noticed we already did something like that when we invoked setPostsPending.

Whether you are invoking an effect from your UI code or from another effect, you can pass arguments directly with the invocation. Those arguments will show up after the effects argument in your effect definition.

Here's an example:

const wrapComponentWithState = provideState({
  initialState: () => ({ thing: "val" }),
  effects: {
    setThing: (effects, newVal) => state => Object.assign({}, state, { thing: newVal })
  }
});

And it could invoked from your component like so:

const Child = injectState(({ state, effects }) => {
  const onClick = () => effects.setThing("new val");
  return (
    <div>
      { `Our "thing" value is: ${state.thing}` }
      <button onClick={onClick}>Click here to change the thing!</button>
    </div>
  );
});

Computed state values

As an application grows, it becomes increasingly important to have effective organizational tools. This is especially true for how you store and transform data.

Consider the following state container:

const wrapComponentWithState = provideState({
  initialState: () => ({
    givenName: "Walter",
    familyName: "Harriman"
  }),
  effects: {
    setGivenName: update((state, val) => ({ givenName: val })),
    setFamilyName: update((state, val) => ({ familyName: val }))
  }
});

Let's say that we're implementing a component and we want to display the user's full name. We might write that component like this:

const WelcomeMessage = injectState(({ state }) => {
  const fullName = `${state.givenName} ${state.familyName}`;
  return (
    <div>
      {`Hi, ${fullName}, and welcome!`}
    </div>
  );
});

That seems like a pretty reasonable piece of code. But, even for a small piece of data like a full name, things can get more complex as the application grows.

What if we're displaying that full name in multiple components? Should we compute it in all those places, or maybe inject state further up the tree and pass it down as a prop? That can get messy to the point where you're passing down dozens of props.

What if the user is in a non-English locale, where they may not place given names before family names? We would have to remember to do that everywhere.

And what if we want to derive another value off of the generated fullName value? What about multiple derived values, derived from other derived values? What if we're not dealing with names, but more complex data structures instead?

freactal's answer to this is computed values.

You've probably run into something like this before. Vue.js has computed properties. MobX has computed values. Redux outsources this concern to libraries like reselect. Ultimately, they all serve the same function: exposing compound values to the UI based on simple state values.

Here's how you define computed values in freactal, throwing in some of the added complexities we mentioned:

const wrapComponentWithState = provideState({
  initialState: () => ({
    givenName: "Walter",
    familyName: "Harriman",
    locale: "en-us"
  }),
  effects: {
    setGivenName: update((state, val) => ({ givenName: val })),
    setFamilyName: update((state, val) => ({ familyName: val }))
  },
  computed: {
    fullName: ({ givenName, familyName, locale }) => startsWith(locale, "en") ?
      `${givenName} ${familyName}` :
      `${familyName} ${givenName}`,
    greeting: ({ fullName, locale }) => startsWith(locale, "en") ?
      `Hi, ${fullName}, and welcome!` :
      `Hellรณ ${fullName}, รฉs szรญvesen!`
  }
});

Note: This is not a replacement for a proper internationalization solution like react-intl, and is for illustration purposes only.

Here we see two computed values, fullName and greeting. They both rely on the locale state value, and greeting actually relies upon fullName, whereas fullName relies on the given and family names.

How might that be consumed?

const WelcomeMessage = injectState(({ state }) => (
  <div>
    {state.greeting}
  </div>
));

In another component, we might want to just use the fullName value:

const Elsewhere = injectState(({ state }) => (
  <div>
    {`Are you sure you want to do that, ${state.fullName}?`}
  </div>
));

Hopefully you can see that this can be a powerful tool to help you keep your code organized and readable.

Here are a handful of other things that will be nice for you to know.

  • Computed values are generated lazily. This means that if the greeting value above is never accessed, it will never be computed.
  • Computed values are cached. Once a computed value is calculated once, a second state retrieval will return the cached value.
  • Cached values are invalidated when dependencies change. If you were to trigger the setGivenName effect with a new name, the fullName and greeting values would be recomputed as soon as React re-rendered the UI.

That's all you need to know to use computed values effectively!

Composing multiple state containers

We started this guide by noting that, while most React state libraries contain state in a single place, freactal approaches things differently.

Before we dive into how that works, let's briefly consider some of the issues that arise with the centralized approach to state management:

  • Oftentimes, it is hard to know how to organize state-related code. Definitions for events or actions live separately from the UI that triggers them, which lives separately from functions that reduce those events into state, which also live separately from code that transforms state into more complex values.
  • While React components are re-usable (see component libraries), complex stateful components are a hard nut to crack. There's this fuzzy line when addressing complexity in your own code that, when crossed, means you should be using a state library vs React's own setState. But how do you make that work DRY across applications and team boundaries?
  • Sometimes you might want to compose full SPAs together in various ways, but if they need to interact on the page or share state in some way, how do you go about accomplishing this? The results here are almost universally ad-hoc.
  • It is an often arduous process when it comes time to refactor your application and move state-dependant components into different parts of your application. Wiring everything up can be tedious as hell.

These are constraints that freactal aims to address. Let's take a look at a minimal example:

const Child = injectState(({ state }) => (
  <div>
    This is the Child.
    {state.fromParent}
    {state.fromGrandParent}
  </div>
));

const Parent = provideState({
  initialState: () => ({ fromParent: "ParentValue" })
})(() => (
  <div>
    This is the Parent.
    <Child />
  </div>
));

const GrandParent = provideState({
  initialState: () => ({ fromGrandParent: "GrandParentValue" })
})(() => (
  <div>
    This is the GrandParent.
    <Parent />
  </div>
));

Its important to notice here that Child was able to access state values from both its Parent and its GrandParent. All state keys will be accessible from the Child, unless there is a key conflict between Parent and GrandParent (in which case Parent "wins").

This pattern allows you to co-locate your code by feature, rather than by function. In other words, if you're rolling out a new feature for your application, all of that new code - UI, state, effects, etc - can go in one place, rather than scattered across your code-base.

Because of this, refactoring becomes easier. Want to move a component to a different part of your application? Just move the directory and update the import from the parents. What if this component accesses parent state? If that parent is still an anscestor, you don't have to change a thing. If it's not, moving that state to a more appropriate place should be part of the refactor anyway.

But one word of warning: accessing parent state can be powerful, and very useful, but it also necessarily couples the child state to the parent state. While the coupling is a "loose" coupling, it still may introduce complexity that should be carefully thought-out.

One more thing.

Child effects can also trigger parent effects. Let's say your UX team has indicated that, whenever an API call is in flight, a global spinner should be shown. But maybe the data is only needed in certain parts of the application. In this scenario, you could define beginApiCall and completeApiCall effects that track how many API calls are active. If above 0, you show a spinner. These effects can be accessed by call-specific effects further down in the state hierarchy, like so:

const Child = injectState(({ state, effects }) => (
  <div>
    This is the Child.
    {state.fromParent}
    {state.fromGrandParent}
    <button
      onClick={() => effects.changeBothStates("newValue")}
    >
      Click me!
    </button>
  </div>
));

const Parent = provideState({
  initialState: () => ({ fromParent: "ParentValue" }),
  effects: {
    changeParentState: (effects, fromParent) => state =>
      Object.assign({}, state, { fromParent }),
    changeBothStates: (effects, value) =>
      effects.changeGrandParentState(value).then(state =>
        Object.assign({}, state, { fromParent: value })
      )
  }
})(() => (
  <div>
    This is the Parent.
    <Child />
  </div>
));

const GrandParent = provideState({
  initialState: () => ({ fromGrandParent: "GrandParentValue" }),
  effects: {
    changeGrandParentState: (effects, fromGrandParent) => state =>
      Object.assign({}, state, { fromGrandParent })
  }
})(() => (
  <div>
    This is the GrandParent.
    <Parent />
  </div>
));

Testing

Before wrapping up, let's take a look at one additional benefit that freactal brings to the table: the ease of test-writing.

If you hadn't noticed already, all of the examples we've looked at in this guide have relied upon stateless functional components. This is no coincidence - from the beginning, a primary goal of freactal was to encapsulate all state in freactal state containers. That means you shouldn't need to use React's setState at all.

Here's the bottom line: because all state can be contained within freactal state containers, the rest of your application components can be "dumb components".

This approach allows you to test your state and your components completely independent from one another.

Let's take a look at a simplified example from above, and then dive into how you might test this application. For the purposes of this example, I assume you're using Mocha, Chai, Sinon, sinon-chai, and Enzyme.

First, our application code:

/*** app.js ***/

import { wrapComponentWithState } from "./state";


export const App = ({ state, effects }) => {
  const { givenName, familyName, fullName, greeting } = state;
  const { setGivenName, setFamilyName } = effects;

  const onChangeGiven = ev => setGivenName(ev.target.value);
  const onChangeFamily = ev => setFamilyName(ev.target.value);

  return (
    <div>
      <div id="greeting">
        { greeting }
      </div>
      <div>
        <label for="given">Enter your given name</label>
        <input id="given" onChange={onChangeGiven} value={givenName}/>
        <label for="family">Enter your family name</label>
        <input id="family" onChange={onChangeFamily} value={familyName}/>
      </div>
    </div>
  );
};

/* Notice that we're exporting both the unwrapped and the state-wrapped component... */
export default wrapComponentWithState(App);

And then our state template:

/*** state.js ***/

import { provideState, update } from "freactal";

export const wrapComponentWithState = provideState({
  initialState: () => ({
    givenName: "Walter",
    familyName: "Harriman"
  }),
  effects: {
    setGivenName: update((state, val) => ({ givenName: val })),
    setFamilyName: update((state, val) => ({ familyName: val }))
  },
  computed: {
    fullName: ({ givenName, familyName }) => `${givenName} ${familyName}`,
    greeting: ({ fullName }) => `Hi, ${fullName}, and welcome!`
  }
});

Next, let's add a few tests!

Stateless functional components

Remember, our goal here is to test state and UI in isolation. Read through the following example to see how you might make assertions about 1) data-driven UI content, and 2) the ways in which your UI might trigger an effect.

/*** app.spec.js ***/

import { mount } from "enzyme";
// Make sure to import the _unwrapped_ component here!
import { App } from "./app";


// We'll be re-using these values, so let's put it here for convenience.
const state = {
  givenName: "Charlie",
  familyName: "In-the-box",
  fullName: "Charlie In-the-box",
  greeting: "Howdy there, kid!"
};

describe("my app", () => {
  it("displays a greeting to the user", () => {
    // This test should be easy - all we have to do is ensure that
    // the string that is passed in is displayed correctly!

    // We're not doing anything with effects here, so let's not bother
    // setting them for now...
    const effects = {};

    // First, we mount the component, providing the expected state and effects.
    const el = mount(<App state={state} effects={effects}/>);

    // And then we can make assertions on the output.
    expect(el.find("#greeting").text()).to.equal("Howdy there, kid!");
  });

  it("accepts changes to the given name", () => {
    // Next we're testing the conditions under which our component might
    // interact with the provided effects.
    const effects = {
      setGivenName: sinon.spy(),
      setFamilyName: sinon.spy()
    };

    const el = mount(<App state={state} effects={effects}/>);

    // Using `sinon-chai`, we can make readable assertions about whether
    // a spy function has been called.  We don't expect our effect to
    // be invoked when the component mounts, so let's make that assertion
    // here.
    expect(effects.setGivenName).not.to.have.been.called;
    // Next, we can simulate a input-box value change.
    el.find("input.given").simulate("change", {
      target: { value: "Eric" }
    });
    // And finally, we can assert that the effect - or, rather, the Sinon
    // spy that is standing in for the effect - was invoked with the expected
    // value.
    expect(effects.setGivenName).to.have.been.calledWith("Eric");
  });
});

That takes care of your SFCs. This should really be no different than how you might have been testing your presentational components in the past, except that with freactal, this is the only sort of testing you need to do for your React components.

State and effects

Next up is state. As you read through the example below, take note that we can make assertions about the initial state and any expected transformations to that state without involving a React component or rendering to the DOM.

/*** state.spec.js ***/

import { wrapComponentWithState } from "./state";

describe("state container", () => {
  it("supports fullName", () => {
    // Normally, you'd pass a component as the first argument to your
    // state template.  However, if you pass no argument to the state
    // template, you'll get back a test instance that you can extract
    // `state` and `effects` from.  Just don't try to render the thing!
    const { effects, getState } = wrapComponentWithState();

    expect(getState().fullName).to.equal("Walter Harriman");

    // Since effects return a Promise, we're going to make it easy
    // on ourselves and wrap all of our assertions from this point on
    // inside a Promise.
    return Promise.resolve()
      // When a Promise is provided as the return value to a Promise's
      // `.then` callback, the outer Promise awaits the inner before
      // any subsequent callbacks are fired.
      .then(() => effects.setGivenName("Alfred"))
      // Now that `givenName` has been set to "Alfred", we can make an
      // assertion...
      .then(() => expect(getState().fullName).to.equal("Alfred Harriman"))
      // Then we can do the same for the family name...
      .then(() => effects.setFamilyName("Hitchcock"))
      // And make one final assertion.
      .then(() => expect(getState().fullName).to.equal("Alfred Hitchcock"));
  });

  // You could write similar assertions here
  it("supports a greeting");
});

That's it for testing!

Conclusion

We hope that you found this guide to be helpful!

If you find that a piece is missing that would've helped you understand freactal, please feel free to open an issue. For help working through a problem, reach out on Twitter, open an issue, or ping us on Gitter.

You can also read through the API docs below!

API Documentation

provideState

This is used to define a state container, which in turn can wrap one of your application components.

const StatefulComponent = provideState({/* options */})(StatelessComponent);

The options argument is an object with one or more of the following keys: initialState, effects, initialize, and computed.

initialState

A function defining the state of your state container when it is first initialized.

This function is invoked both on the server during a server-side render and on the client. However, you might employ environment detection in order to yield divergent results.

provideState({
  initialState: () => ({
    a: "value will",
    b: "set here"
  })
})

Component props can be passed to initialState like so :

provideState({
  initialState: ({ value }) => ({
    a: value,
    b: "set here"
  })
})

effects

Effects are the mechanism by which state is updated.

The effects value should be an object, where the keys are function names (that you will later) and the values are functions.

Each effect will be provided one or more arguments: an effects reference (see note below), and any arguments that are passed to the function when they're invoked in application code.

The return value is either 1) a function that takes in old state and returns new state or, 2) a Promise that resolves to #1.

This may seem opaque, so please refer to the guide for information on how to use them effectively.

provideState({
  effects: {
    doThing: (effects, argA) =>
      Promise.resolve(state => Object.assign({}, state, { val: argA }))
  }
});

NOTE 1: The effects are called synchronously so you that you can use directly any passed events:

provideState({
  effects: {
    onInputChange: (effects, event) => {
      const { value } = event.target
      return state =>
        Object.assign({}, state, { inputValue: value })
    }
  }
});

const MyComponent = injectState(({ effects, state }) => (
  <input onChange={effects.onInputChange} value={state.inputValue} />
))

NOTE 2: The effects object that is passed to each effect is not the same as the outer effects object that you define here. Instead, that object is a composition of the hierarchy of stateful effects.

initialize

Each state container can define a special effect called initialize. This effect has props passed in as a second argument and will be implicitly invoked in two circumstances:

  1. During SSR, each state container with an initialize effect will invoke it, and the rendering process will await the resolution of that effect before continuing with rendering.
  2. When running in the browser, each state container with an initialize effect will invoke it when the container is mounted into the DOM.

Note: this effect will NOT be passed down to a component's children.

computed

The computed object allows you to define compound state values that depend on basic state values or other computed values.

The value provided as the computed option should be an object where each key is the name by which the computed value will be referenced, and each value is a function taking in state and returning a computed value.

provideState({
  initialState: () => ({
    a: "value will",
    b: "set here"
  }),
  computed: {
    aPlusB: ({ a, b }) => `${a} + ${b}`, // "value will + set here"
    typeOfAPlusB: ({ aPlusB }) => typeof aPlusB // "string"
  }
})

Props can't be passed to computed

middleware

Middleware is defined per state container, not globally. Each middleware function will be invoked in the order provided whenever a state change has occurred.

With middleware, you should be able to inject new state values, intercept effects before they begin, track when effects complete, and modify the way in which sub-components interact and respond to state containers further up the tree.

To write middleware effectively, you'll probably want to take a look at the Freactal's internal buildContext method. Fortunately it is pretty straightforward.

The following is an example that will log out whenever an effect is invoked, the arguments it was provided, and when the effect completed:

provideState({
  middleware: [
    freactalCxt => Object.assign({}, freactalCxt, {
      effects: Object.keys(freactalCxt.effects).reduce((memo, key) => {
        memo[key] = (...args) => {
          console.log("Effect started", key, args);
          return freactalCxt.effects[key](...args).then(result => {
            console.log("Effect completed", key);
            return result;
          })
        };
        return memo;
      }, {})
    })
  ]
})

injectState

While provideState supplies the means by which you declare your state and its possible transitions, injectState is the means by which you access state and effects from your UI code.

By default, injectState will detect the keys that you access in your component, and will only force a re-render if those keys change in the upstream state container.

const StatelessComponent = ({ state: { myValue } }) =>
  <div>{ myValue }</div>
const WithState = injectState(StatelessComponent);

In the above example, StatelessComponent would only be re-rendered a second time if myValue changed in the upstream state container.

However, it is possible to explicitly define which keys you want to "listen" to. When using this form, the keys that you specify are injected into the wrapped component as props.

const StatelessComponent = ({ myValue }) =>
  <div>{ myValue }</div>
const StatefulComponent = injectState(StatelessComponent, ["myValue", "otherValueToo"]);

In this example, StatelessComponent would re-render when myValue changed, but it would also re-render when otherValueToo changed, even though that value is not used in the component.

hydrate and initialize

These functions are used to deeply initialize state in the SSR context and then re-hydrate that state on the client. For more information about how to use these functions, see the below documentation on Server-side Rendering.

Helper functions

You may find the following functions handy, as a shorthand for common tasks.

update

This handy helper provides better ergonomics when defining an effect that updates state.

It can be consumed like so:

import { provideState, update } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: update({ setThisKey: "to this value..." })
  }
});

Which is equivalent to the following:

import { provideState } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: () => state => Object.assign({}, state, { setThisKey: "to this value..." })
  }
});

When your update is dependant on the previous state you can pass a function, like so:

import { provideState, update } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: update(state => ({ counter: state.counter + 1 }))
  }
});

Which is equivalent to the following:

import { provideState } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: () => state => Object.assign({}, state, { counter: state.counter + 1 })
  }
});

Any arguments that are passed to the invocation of your effect will also be passed to the function you provide to update.

I.e.

effects: {
  updateCounterBy: (effects, addVal) => state => Object.assign({}, state, { counter: state.counter + addVal })
}

is equivalent to:

effects: {
  myEffect: update((state, addVal) => ({ counter: state.counter + addVal }))
}

mergeIntoState

update is intended for synchronous updates only. But writing out a state-update function for asynchronous effects can get tedious. That's where mergeIntoState comes in.

mergeIntoState(newData)

... is exactly equivalent to...

state => Object.assign({}, state, newData)

Here's what it might look like in practice:

export const getData = (effects, dataId) => fetch(`http://some.url/${dataId}`)
  .then(response => response.json())
  .then(body => mergeIntoState({ data: body.data }));

Server-side Rendering

Historically, server-side rendering of stateful React applications has involved many moving pieces. freactal aims to simplify this area without sacrificing the power of its fractal architecture.

There are two parts to achieving SSR with freactal: state initialization on the server, and state hydration on the client.

Keep in mind that, if you have a state container whose state needs to be initialized in a particular way, you should take a look at the initialize effect.

freactal supports both React's built-in renderToString method, as well as the newer Rapscallion.

with React#renderToString

On the server, you'll need to recursively initialize your state tree. This is accomplished with the initialize function, provided by freactal/server.

/* First, import renderToString and the initialize function. */
import { renderToString } from "react-dom/server";
import { initialize } from "freactal/server";

/*
  Within the context of your Node.js server route, pass the root component to
  the initialize function.
 */
initialize(<StatefulRootComponent rootProp="hello" />)
  /* This invocation will return a Promise that resolves to VDOM and state */
  .then(({ vdom, state }) => {
    /* Pass the VDOM to renderToString to get HTML out. */
    const appHTML = renderToString(vdom);
    /*
      Pass your application HTML and the application state (an object) to a
      function that inserts application HTML into <html> and <body> tags,
      serializes state, and inserts that state into an accessible part of
      the DOM.
    */
    const html = boilerplate(appHTML, state);
    /* Finally, send the full-page HTML to the client */
    return res.send(html).end();
  })

You can find a full freactal example, including a server and SSR here.

with Rapscallion

The above method involves a partial render of your application (initialize), ultimately relying upon React.renderToString to transform the VDOM into an HTML string. This is because renderToString is synchronous, and freactal is asynchronous by design.

Because Rapscallion is also asynchronous by design, there is even less ceremony involved.

/* First, import Rapscallion's render and the captureState function. */
import { render } from "rapscallion";
import { captureState } from "freactal/server";

/*
  Within the context of your Node.js server route, invoke `captureState` with your root component.
 */
const { Captured, state } = captureState(<StatefulRootComponent rootProp="hello" />);

/* Pass the <Captured /> component to Rapscallion's renderer */
render(<Captured />)
  .toPromise()
  .then(appHTML => {
    /*
      At this point, the `state` object will be fully populated with your
      state tree's data.

      Pass your application HTML and state to a function that inserts
      application HTML into <html> and <body> tags, serializes state, and
      inserts that state into an accessible part of the DOM.
    */
    const html = boilerplate(appHTML, state);
    /* Finally, send the full-page HTML to the client */
    return res.send(html).end();
  });

Hydrate state on the client

Using one of the above methods, you can capture your application state while server-side rendering and insert it into the resulting HTML. The final piece of the SSR puzzle is re-hydrating your state containers inside the browser.

This is accomplished with hydrate in the context of your initialState function.

Assuming you've serialized the SSR state and exposed it as window.__state__, your root state container should look something like this:

import { provideState, hydrate } from "freactal";

const IS_BROWSER = typeof window === "object";
const stateTemplate = provideState({
  initialState: IS_BROWSER ?
    hydrate(window.__state__) :
    () => { /* your typical state values */ },
  effects: { /* ... */ },
  computed: { /* ... */ }
});

In SSR, your typical state values will be provided as your initial state. In the browser, the initial state will be read from window.__state__.

Assuming you've done this with your root state container, you can similarly re-hydrate nested state containers like so:

import { provideState, hydrate } from "freactal";

const IS_BROWSER = typeof window === "object";
const stateTemplate = provideState({
  initialState: IS_BROWSER ?
    hydrate() :
    () => { /* your typical state values */ },
  effects: { /* ... */ },
  computed: { /* ... */ }
});

Note that there is no need to pass window.__state__ to the hydrate function for nested state containers.

Maintenance Status

Archived: This project is no longer maintained by Formidable. We are no longer responding to issues or pull requests unless they relate to security concerns. We encourage interested developers to fork this project and make it their own!

freactal's People

Contributors

agurtovoy avatar chrisbolin avatar david-davidson avatar divmain avatar dmiller9911 avatar everdimension avatar foxyblocks avatar ghemid-mohamed avatar henryluki avatar jpdriver avatar julien-f avatar knisterpeter avatar markacola avatar rafalfilipek avatar ryan-roemer avatar sammdec avatar spoike avatar zebulonj avatar zhengjunxin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

freactal's Issues

State not being updated

State is available to the component, so does the effects. (They are in different folders, effects is one folder above, dunno if that makes any difference to my problem).

// initial-state.js
export default () => ({
  selected: "internal",
  isOpen: true
})
// effects.js
export default {
  handleDialog: () => state => ({ ...state, isOpen: !state.isOpen })
}

PS: I've tried SoftUpdate and Object.assign as well in the above function.

// React Component that triggers the effects
const NavButtons = ({ effects }) => (
  <Wrapper>
    <RaisedButton primary label="Request Appraisal" onClick={effects.handleDialog} />
  </Wrapper>
);

NavButtons.propTypes = {
  effects: PropTypes.shape({
    handleDialog: PropTypes.func.isRequired
  }).isRequired
};

export default injectState(NavButtons);
// React component that holds the mentioned state
const RequestAppraisal = ({ state, effects }) => {
  const actions = [
    <RaisedButton label="Submit" primary onTouchTap={effects.handleDialog} />
  ];

  return (
    <Dialog
      autoScrollBodyContent
      title="Create new feedback round"
      actions={actions}
      modal={false}
      open={state.isOpen}
    >
      <RowWrapper>
        <RowTitle>Survey Template</RowTitle>
        <Wrapper>
          <SurveyTemplate />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <RowTitle>Type of Feedback</RowTitle>
        <Wrapper>
          <TypeOfFeedback />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <RowTitle>Add Assessors</RowTitle>
        <Wrapper>
          <AddAssessors />
        </Wrapper>
      </RowWrapper>
      <RowWrapper>
        <Wrapper>
          <Assessors />
        </Wrapper>
      </RowWrapper>
    </Dialog>
  )
}

RequestAppraisal.propTypes = {
  state: PropTypes.shape({
    isOpen: PropTypes.bool.isRequired
  }).isRequired,
  effects: PropTypes.shape({
    handleDialog: PropTypes.func.isRequired,
  }).isRequired
};

export default provideState({
  initialState
})(injectState(RequestAppraisal));

The problem is that the despite being available to the component, the state is only updated if I use the state/effect in the parent component. If I just inject/provide without using them, the state does not update.

Here is an example:
The component above doesn't update if the App.js written like this:

const Dashboard = () => (
  <div>
    <NavBar />
    <Wrapper>
      <UserInfo />
      <DashboardData />
      <RequestAppraisal />
    </Wrapper>
  </div>
);

export default withState(injectState(Dashboard));

But it does update if App.js has props state:

// NavButtons component is inside NavBar.
const Dashboard = ({ state }) => (
  <div>
    {console.log(state.isOpen)}
    <NavBar />
    <Wrapper>
      <UserInfo />
      <DashboardData />
      <RequestAppraisal />
    </Wrapper>
  </div>
);

export default withState(injectState(Dashboard));

Is that the correct behaviour? Because like in my example, I don't need to use the state/effects in the parent component.
Or I am doing something wrong?

Thanks

Question: why do I have to pass state and effects into my components?

Great library, looking forward to trying it out in real projects.
Is there any reason why I have to work with state and effects props in my components? Any reason for not having some sort of mapping functionality like in Redux, i.e. mapStateToProps/mapEffectsToProps?
At the moment API feels slightly angular-esque and if I was to use dependency injection analogy - currently I have to pass an entire container into my components rather than individual dependencies.
Hope this makes sense.

Question: Initialize state to props?

What's the best way to initialize state to a specific prop value?
Or, how do I access props within initialState?
Obviously, using React's state you would just set the initial state to this.props.value, but what is the correct way to do so with freactal?

For example:

const wrapComponentWithState = provideState({
  initialState: () => ({
    testValue:   //Initialize to prop value here
  })
})

Provide a UMD build + `es/` output.

Some people still use/prefer UMD libraries. Providing one also means you could load freactal from a CDN like unpkg, which would be useful for reproducing issues (creating JSFiddles, for example)

Use Softupdate edit Textfield, cursor jumps to the end of textfeild

Hi There,
I face a issue when I use softupdate method to edit Textfield.
I use [email protected] and [email protected].

I try to use softupdate to reset my state value, however, when I try to insert a word within old value. I only could add the first character and then the cursor just jumps to the end.

for example, if I want add "World" before string "University". what I got is "Wuniveristyorld". since after type "W", the cursor jumps to end of textfield.

initialState: () => ({streetNameNumber: ''})

in effects object
setTextValue: softUpdate((state, key, value) => ( {[key]: value })),

in render

<TextField floatingLabelText="Street Number/Name" name="streetNameNumber" id="streetNameNumber" value={state.streetNameNumber} onChange={e => effects.setTextValue(e.target.name, e.target.value)}/>

Anyone know what is going on?

very appreciate.

recompose-like local state, but with the freactal API

Right now when you want some states, you have to create and provide it through the context using provideState and then inject it into your component with injectState. This is great when you are dealing with state containers you intend to access from multiple components and in that regards they are pretty much akin to a Mobx Store with their respective Provider and Inject. (In respect to how they are declared and injected).

However when I want to to provide a state only for a given component, I kinda want to encapsulate the state with my component without exposing it though the context.

What do you think about introducing a withState which takes the same object as provideState and create an HoC that I can use to provide state through props directly to my component ?

Zen of Python

Super excited to try this out. Mad props to you guys at formidable ๐ŸŽ‰

Would someone care to help me see how freactal fits alongside some of the points from the zen of python? I'm new to this set of 'zen' principles. So far I like them, I'd like to use them myself. It'd be good to know how you interpret these points and see how they align with freactal.

  • Explicit is better than implicit.
  • Simple is better than complex.
  • Complex is better than complicated.
  • Flat is better than nested.
  • Sparse is better than dense.
  • Readability counts.

State Exposed to Effects?

Is there a way to read state in effects, prior to the atomic state transformation?

In redux, a prototypical example would be:

export function fetchPostsIfNeeded(subreddit) {
  // Note that the function also receives getState()
  // which lets you choose what to dispatch next.

  // This is useful for avoiding a network request if
  // a cached value is already available.

  return (dispatch, getState) => {
    if (shouldFetchPosts(getState(), subreddit)) {
      // Dispatch a thunk from thunk!
      return dispatch(fetchPosts(subreddit))
    } else {
      // Let the calling code know there's nothing to wait for.
      return Promise.resolve()
    }
  }
}

In that example, getState() is used to inspect whether a fetch is needed.

Add `namespace` option to `provideState`

When provideState is invoked like so:

provideState({
  namespace: "myNamespace",
  initialState: () => ({ value: "myValue" }),
  effects: { setVal: softUpdate((state, value) => ({ value })) }
});

All state values and effect functions will be silo'd within that namespace. Consuming from a child component would look like:

injectState(({ state, effects }) => (
  <div>
    {state.myNamespace.value}
    <button
      onClick={() => effects.myNamespace.setVal("newValue")}
    >
      Click me!
    </button>
  </div>
));

Using async functions for effects

I have the following effects:

const setLoading = softUpdate(({ loading }, val) => ({ loading: loading += val ? 1 : -1 }));

const getLayouts = efects => (async () => {
  await effects.setLoading(true);
  const {data: layouts} = await axios.get('/layouts');
  await effects.setLoading(false);
  
  return state => ({ ...state, layouts });
})();

const effects = {
  getLayouts,
  setLoading
};

export default effects;

However, the await effects.setLoading call does not seem to actually trigger the setLoading effect.

Is there a recommended way I can use async functions for effects?

Consolidate `softUpdate` and `hardUpdate`?

Right now, freactal provides a hardUpdate helper:

import { provideState, hardUpdate } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: hardUpdate({ setThisKey: "to this value..." })
  }
});

...and a softUpdate helper:

import { provideState, softUpdate } from "freactal";
const wrapComponentWithState = provideState({
  // ...
  effects: {
    myEffect: softUpdate(state => ({ counter: state.counter + 1 }))
  }
});

... where the core difference is that hardUpdate takes a partial state object (independent of previous state), while softUpdate takes a function that's called with state and returns a partial state object.

What if we combined both into a single update helper that 1.) behaves like hardUpdate if you call it with an object and 2.) behaves like softUpdate if you call it with a function? The idea is that both of these would be possible:

effects: {
  resetCounter: update({ counter: 0 }),
  incrementCounter: update(state => ({ counter: state.counter + 1 }))
}

API change Proposal

Hi โœ‹ ,

I've been thinking about my problem (see #59 ) and I have a proposal to solve this.

Some vocabulary

First I think it might be useful to clarify some vocabulary :

modifier : (prevState) => nextState

A modifier take a state and return a state ยฏ_(ใƒ„)_/ยฏ.

Example :

const counterIncrement = (state) => ({ ...state, counter: state.counter + 1 })

softModifier

It might be useful to create a helper like this :

const softModifier = (newStateCreator) => (state) => ({ ...state, ...(newStateCreator(state)) })

// And then to use it :

const counterIncrement = softModifier(state => ({ counter: state.counter + 1 }))

modifierCreator : (...params) => modifier

A modifierCreator is just a function that return a modifier.
Example :

const counterIncrementBy = (amount) => (state) => ({ ...state, counter: state.counter + amount })

// same as

const counterIncrementBy = (amount) => softModifier(state => ({ counter: state.counter + amount }))

effect : (effects, state) => Promise(modifier)

An effect would be similar to what it's now but it will not accept additional arguments and instead it will take the current state as second argument.
Just like in current API the result would be wrapped in a Promise if necessary so we don't have to create a promise for synchronous effects.

Example :

const incrementCounter = (effects, state) => counterIncrement;

// same as
const incrementCounter = (effects, state) => (state) => ({ ...state, counter: state.counter + 1 });

// you can also use `modifierCreator` :
const incrementCounterBy2 = (effects, state) => counterIncrementBy(2);

effectCreator = (...params) => affect

Finally an effectCreatoris a function that return a effect.
This is what you would use to pass argument to effect.
Example:

const updateCounterBy = (amount) => (effects, state) => counterIncrementBy(amount);

// but we can omit effects and state here
const updateCounterBy = (amount) => () => counterIncrementBy(amount);

API Change Proposal

The idea is that instead of declaring effects like in the current API we would declare effectCreator.

// we would replace this :
updateCounterBy: (effects, addVal) => state => ({ ...state, counter: state.counter + addVal })

// by this
updateCounterBy: (addVal) => () => state => ({ ...state, counter: state.counter + addVal })

A note about composition

An interesting consequence of modifiers is that it's easy to compose then :

const incrementTwice = () => () => compose(counterIncrement, counterIncrement);
// we might want some helper so we can write
const incrementTwice = modifierEffect(compose(counterIncrement, counterIncrement));

Waiting for you feedback about this ๐Ÿค”
I could create a PR if you like the idea ๐Ÿ˜ƒ

Error in provide when `componentWillUnmount` called without `componentDidMount`

If there is an error thrown in a child render method under provide then componentDidMount won't fire before componentWillUnmount, causing this.unsubscribe to be undefined.

When componentWillUnmount is called to unmount the partial tree this.unsubscribe is called, resulting in TypeError: this.unsubscribe is not a function at StatefulComponent.componentWillUnmount. This masks the actual error being thrown in the child render method, making it difficult to debug in development.

Add support to use immutable.js data structures

Currently All my projects using redux with immutable.js instead of Object.assign approach.

If you do not mind, I could help you and make a pull request of immutable.js lib usage for better performance and all goods which comes with immutability.

RFC: hide usage of context from user

Context is still considered an experimental API and the React team recommends avoiding it in most situations.

If you aren't an experienced React developer, don't use context. There is usually a better way to implement functionality just using props and state.

If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.

If freactal requires that user's to explicitly use contextTypes I believe it will hurt adoption as it's unlikely community leaders or the React team will support an API that requires new users to use context directly. While context is still used in a number of popular data management libraries, it's typically hidden from the user via HOCs. I recommend one of two approaches:

  1. Attach contextTypes to the component passed to addState for the user, so it automatically gets the context data.

  2. Only attach contextTypes to StatefulComponent and pass state and effects down via props instead of asking the user to use context

I would prefer option 2 if possible as it removes context from the user-facing API completely.

cc @divmain @kenwheeler

Testing State Example doesn't work

The testing the state container part of the Readme doesn't work.

const wrapComponentWithState = provideState({
  initialState: () => ({
    givenName: "Walter",
    familyName: "Harriman"
  }),
  effects: {
    setGivenName: softUpdate((state, val) => ({ givenName: val })),
    setFamilyName: softUpdate((state, val) => ({ familyName: val }))
  },
  computed: {
    fullName: ({ givenName, familyName }) => `${givenName} ${familyName}`,
    greeting: ({ fullName }) => `Hi, ${fullName}, and welcome!`
  }
});

const { effects, getState } = wrapComponentWithState();
console.log(wrapComponentWithState())
getState().fullName.should.equal("Walter Harriman");

This is the output I'm getting,

Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
{ [Function: StatefulComponent]
  childContextTypes: { freactal: { [Function: bound checkType] isRequired: [Function: bound checkType] } },
  contextTypes: { freactal: { [Function: bound checkType] isRequired: [Function: bound checkType] } } }
/home/pyros2097/Code/rad/test/abc.js:56
getState().fullName.should.equal("Walter Harriman");
^

TypeError: getState is not a function
    at Object.<anonymous> (/home/pyros2097/Code/rad/test/abc.js:49:1)
    at Module._compile (module.js:571:32)
    at loader (/home/pyros2097/Code/rad/node_modules/babel-cli/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/home/pyros2097/Code/rad/node_modules/babel-cli/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Function.Module.runMain (module.js:605:10)
    at Object.<anonymous> (/home/pyros2097/Code/rad/node_modules/babel-cli/lib/_babel-node.js:154:22)
    at Module._compile (module.js:571:32)

I'm using,
babel-node 6.24.0

Issues with nullified events

I am experiencing an issue when directly passing an effect to an element as an event handler.

It is to do with the empty https://github.com/FormidableLabs/freactal/blob/master/src/effects.js#L9 causing the effectFn to be defered to the next tick, after which React has nullified the event, making it impossible to extract the values purely via effects.

Changing:

Promise.resolve()
      .then(() => effectFn(effects, ...args))

to:

Promise.resolve(effectFn(effects, ...args))

Fixes the issue by calling effectFn immediately. I am not sure if this will negatively affect the timing of anything else.

I can see in the testing example in the readme (https://github.com/FormidableLabs/freactal/blob/master/README.md#L640) that a wrapper function is used in the render to immediately extract the value from the element.
This works fine, however I have always avoided function declaration within render for performance reasons.

Feel free to close this if it isn't considered an issue, however it is something that I have run into.

Fetching data

I've been spending way too long on this, is there some reason this doesn't work?

export const getWeather = (effects, coords) => axios.get(`http://api.openweathermap.org/data/2.5/weather?lat=${coords[1]}&lon=${coords[0]}&units=metric&appid=APIKEY`).then(response => hardUpdate({ weather: response.data.main }) );

Change both states on different parent states

Just had read through the docs and can't wait to try it. However I have came up with questions when reading sections on changeBothStates effect.

In the doc the effect is defined in Parent state, which it accesses an effect on GrandParent. This seem like a design that asks for trouble as the Parent state should be aware of the information in GrandParent. This causes questions on separation of concerns. What if changeGrandParentState has been removed or changed to multiple functions? I would have to change changeBothStates in Parent effects and all states that accesses changeGrandParentState effect. What is the thoughts behind the merge all effects into one global effects design?

Another concern is that instead of Promise.then(), in some cases Promise.all() may be preferred, in Redux world it would be one action triggers changes in multiple reducers.
Would this work for these situations?

changeBothStates: (effects, value) =>
      Promise.all([
            effects.changeGrandParentState(value),
            effects.changeParentState(value),
      ])

Compatible with webpack Hot Module Replacement?

Have you used freactal with webpack hot module replacement and the react-hot-loader? Just built a small test project with freactal and am not seeing component updates via the webpack-dev-server when I update files. Perhaps shouldComponentUpdate is preventing the re-render?

I'm going to look more closely as I'm able, but wanted to put this question out there in case others have an answer.

Possible error in the examples in the docs relating to effects

The README gives the following examples for effects:

addOne: () => state => Object.assign({}, state, { counter: state.counter + 1 })
/* vs */
addOne: () => state => Promise.resolve(Object.assign({}, state, { counter: state.counter + 1 }))
/* vs */
addOne: () => state => new Promise(resolve => resolve(Object.assign({}, state, { counter: state.counter + 1 })))

To put it explicitly, the value you provide for each key in your effects object is:

  1. A function that takes in some arguments (we'll cover those shortly) and returns...
  2. A promise that resolves to...
  3. A function that takes in state and returns...
  4. The updated state.

...

So, you might define the following effect:

updatePosts: () => fetch("/api/posts")
  .then(result => result.json())
  .then(({ posts }) => state => Object.assign({}, state, { posts }))

The fetch example matches the flow described (and makes sense), but the first set of examples above are functions that take some arguments that return functions that take in state and return promises. I.e. they have 2 and 3 the wrong way round. Is this also valid?

Happy to PR if the addOne examples need changing, or to shut up if I've just misunderstood.

Making an async call in effects.initialize with nested container components leads to multiple service calls

Hi @divmain,

Thanks for freactal I really love how it composes things. I have been playing with it for past few days and wanted your opinion on few things I've encountered. These may very well be an issue with how I am using the library.

I created a simple client-side rendered app with two state container components (i.e. components wrapped with provideState one at main level and the second one is nested within parent).

Here is the gist with complete code: https://gist.github.com/niki4810/57f9ca785ccfe00c9789b16668e4c6a4

These are the issues I am noticing:

  1. Multiple fetch requests which calling service from effects.initialize:
    I am using the root containers, effects.initialize to make an fetch call to initialize the state data. I noticed that when I do this, this results in multiple fetch requests. I don't notice the same behavior when I remove the nested container component.
    • is it recommended to make fetch calls using effect.initialize ?
    • If not what's the ideal way to bootstrap data from client side?
      One potential solution I figured is to have a child component which is wrapped with injectState call the async effect from within componentDidMount function. For e.g:
class Title extends React.Component {
  componentDidMount() {
    this.props.effects.getItemDetails(); // async call to fetch initial state data
  }
  render () {
    const {selectedItem = {}} = state;
    const {title = ""} = selectedItem;
    return (
       <h1>{title}</h1>
     );
   }
}
const StatefulTitle = injectState(Title);

This solution fixes the multiple network requests issue, but not sure if this is recommended.

  1. If initialState returns empty object, the state does not get's merged when server returns data
    When my root container component returns an empty object as initial state as show below
initialState: () => {
    return { };
  },
  effects: {
    getItemDetails: effects => fetch("http://output.jsbin.com/nuxodel.json")
    .then(result => result.json())
    .then(data => state => Object.assign({}, state, data)),
  },

If I later on call effects.getItemDetails call to my data providers (for e.g. here my service : http://output.jsbin.com/nuxodel.json), the state does not get merged correctly. Am I doing something wrong ?

Please let me know if you need further code samples. Looking forward for you feedback.

Thanks,
Nikhilesh

had to modify code in guide to get it to work

this

const wrapWithPending = (pendingKey, cb) => effects  =>
  effects.setFlag(pendingKey, true)
    .then(cb)
    .then(value => effects.setFlag(pendingKey, false).then(() => value));

needs to be

const wrapWithPending = (pendingKey, cb) => effects  =>
  effects.setFlag(pendingKey, true)
    .then(() => cb)
    .then(value => effects.setFlag(pendingKey, false).then(() => value));

Providing effect payload and name to middleware

Currently, middleware is just invoked with the entire state tree and effects list on every update. Middleware is especially useful when it can respond to a specific subset of effects, as well as know what that effect contained.

The existing recommendation is to just overwrite the effects with a wrapping utility, but that doesn't seem consistent with what a middleware API should provide since that means you'd be redefining your effects every time an effect is triggered, which I can't imagine is great for performance either. You want your middleware to get the data it needs by default as well.

Can middleware be invoked at a different point in the code path so it has access to effect names
and effect payload without having to redefine effects on every update?

Child component that always gets initial state, never updates

In the following code, I have a parent component providing state with an effect to toggle a value.
There are 4 copies of a child component that displays and toggles the value.
The 4 are mounted and wrapped in different ways.
All 4 can use the effect to toggle the value, only 3 ever show the updated value.

For the life of me, I can't figure out why that one doesn't work! Am I doing something weird? Is this a bug?

Thanks in advance!

import React from 'react'
import { provideState, injectState, softUpdate } from 'freactal'

const wrapParentWithState = provideState({
  initialState: () => ({
    toggleMe: true
  }),
  effects: {
    toggle: softUpdate(state => ({ toggleMe: !state.toggleMe }))
  }
})

const ParentWithState = wrapParentWithState(() => (
  <Parent>
    props.children: <Child />
    <hr />
    BROKEN props.children, with provideState: <ChildWithState />
  </Parent>
))

const Parent = injectState(({ state: { toggleMe }, children }) => (
  <div>
    <div>Parent: toggleMe is {toggleMe ? 'true' : 'false'}</div>
    <hr />
    <div>{children}</div>
    <hr />
    <div>direct: <Child /></div>
    <hr />
    <div>direct, with provideState: <ChildWithState /></div>
  </div>
))

const Child = injectState(({ state: { toggleMe }, effects: { toggle } }) => (
  <div>
    <button onClick={() => toggle()}>Toggle</button>
    toggleMe is {toggleMe ? 'true' : 'false'}
  </div>
))

const wrapChildWithState = provideState({
  initialState: () => ({}),
  effects: {}
})

const ChildWithState = wrapChildWithState(Child)

export default ParentWithState

Accessing component props in effects

I'm trying out freactal for an internal admin tool, and I'm running into an issue with handling history changes as a response to effects.

I'm using react-router@v4 for routing, which no longer exposes a history singleton, meaning that I have to wrap my components in withRouter to get access to the history object on my component's props and be able to make changes to it. However, I'd like to redirect the user after making an API call, but there isn't a way to get at the props in an effect, so I end up writing component methods like these:

addAsset = async params => {
  const { effects: { addAsset }, history } = this.props;
  await addAsset(params);
  history.push('/marketing/assets');
};

I've thought about wrapping my root component in withRouter and then setting the history in my state, but then I still can't access the state within an effect to be able to make changes to it.

Do you have any thoughts on how to best get around this issue without having to write a bunch of boilerplate component methods?

rapscallion compatibility

Ironically, the VDOM partial render in freactal doesn't play nice with rapscallion's caching technique. A small extension library may be necessary for freactal to rely on rapscallion's render rather than its own internal partial-render implementation.

How does this compare to redux-saga?

The README states that it could effectively replace redux and redux-saga. The main reason (for me at least) to use redux-saga over redux-thunk is testability.

The testing section is a bit sparse on testing side effects (in the form of e.g. API calls). Could you provide some more examples?

Breach of contract, A component manages and contains its own state

I was reading the new article by @tptee on freactal which puts some emphasis on the breach on contract that for example Redux is forcing on us because a component should manage and contain its own state.

This kinda implies that freactal does not do this and therefore doesn't allow arbitrary descendants to pick state from ancestors. However the documentation says otherwise:

Because Child is contained within the subtree where Parent is the root node, it has access to the Parent component's state.

This seems to imply that no matter how deep the child is, if it's an descendant of the parent, it can access and mutate the ancestor's state which essentially breaks the encapsulation.

Now this is a super useful behaviour when you actually need to share state between components meaning the state does not belong to a given component. However when you do need to create a state that does belong to a given component alone, it does not seem that there is a way to do it right now and that's why i had opened #22 to discuss this.

So is my understanding on how freactal manage and provide state to ancestors wrong or is the article incorrect and little bit misleading in that regard ?

On a side note, while the example of child / parent / grand-parent has been fixed in the Readme on Github, the article is still using the incorrect one.

And don't get me wrong, I very much like this project and it's great article, I just find the stance on breach of contract a bit misleading because as far as I see it, freactal is in the same boat as redux when it comes to encapsulation of component's state for now.

Calling one effect from another

How can I simply call one synchronous effect from another (synchronous) effect? In my example below, the reactLevel* effects call the changeLevel effect. I'd like to write it very cleanly, with resetLevelBad, but that (spoiler) doesn't work.

export default withState({
  ...
  effects: {
    changeLevel: (effects, level) => state => doSomethingInteresting(level),
    resetLevelBad: effects => state => effects.changeLevel(state.level),
    resetLevelGood: effects => state => {
      effects.changeLevel(state.level);
      return state; // why do I have to return state here?
    },
  },
});

Specifically, resetLevelBad sets the state to undefined for one tick (I know this because my computed functions were erroring), and then changeLevel is called and all is well again. Maybe have freactal assume that returning a Promise from an effect means don't alter the state? Or better yet, just wait on that promise.

How to access state after effects complete in middleware?

In freactal v1.1.0, I want to track the state changes in middleware for debugging just like what redux-logger did. However I find that I can't access the latest state after effects complete in middleware.

Am I missing anything? And it would be fabulous if you could help me out. Thanks!

Issues with docs code examples

setGivenName and setFamilyName should be effects.setGivenName and effects.setFamilyName

/*** state.spec.js ***/

import { wrapComponentWithState } from "./state";

describe("state container", () => {
  it("supports fullName", () => {
    // Normally, you'd pass a component as the first argument to your
    // state template.  However, so long as you don't try to render the
    // thing, you can get by without doing so, which makes testing your
    // state container that much easier.
    const { effects, getState } = wrapComponentWithState();

    expect(getState().fullName).to.equal("Walter Harriman");

    // Since effects return a Promise, we're going to make it easy
    // on ourselves and wrap all of our assertions from this point on
    // inside a Promise.
    return Promise.resolve()
      // When a Promise is provided as the return value to a Promise's
      // `.then` callback, the outer Promise awaits the inner before
      // any subsequent callbacks are fired.
      .then(() => setGivenName("Alfred"))
      // Now that `givenName` has been set to "Alfred", we can make an
      // assertion...
      .then(() => expect(getState().fullName).to.equal("Alfred Harriman"))
      // Then we can do the same for the family name...
      .then(() => setFamilyName("Hitchcock"))
      // And make one final assertion.
      .then(() => expect(getState().fullName).to.equal("Alfred Hitchcock"));
  });

  // You could write similar assertions here
  it("supports a greeting");
});

injectState is never used.

/*** app.js ***/

import { injectState } from "freactal";
import { wrapComponentWithState } from "./state";


export const App = ({ state, effects }) => {
  const { givenName, familyName, fullName, greeting } = state;
  const { setGivenName, setFamilyName } = effects;

  const onChangeGiven = ev => setGivenName(ev.target.value);
  const onChangeFamily = ev => setFamilyName(ev.target.value);

  return (
    <div>
      <div id="greeting">
        { greeting }
      </div>
      <div>
        <label for="given">Enter your given name</label>
        <input id="given" onChange={onChangeGiven} value={givenName}/>
        <label for="family">Enter your family name</label>
        <input id="family" onChange={onChangeFamily} value={familyName}/>
      </div>
    </div>
  );
};

/* Notice that we're exporting both the unwrapped and the state-wrapped component... */
export default wrapComponentWithState(App);

This one is totally confusing. Who is supposed to render what? Where is GrandChild ?

const Child = injectState(({ state }) => (
  <div>
    This is the GrandChild.
    {state.fromParent}
    {state.fromGrandParent}
  </div>
));

const Parent = provideState({
  initialState: () => ({ fromParent: "ParentValue" })
})(() => (
  <div>
    This is the Child.
    <GrandChild />
  </div>
));

const GrandParent = provideState({
  initialState: () => ({ fromGrandParent: "GrandParentValue" })
})(() => (
  <div>
    This is the Parent.
    <Child />
  </div>
));

Effect that does not change state

For example, effects like this:

effects: {
  commentVote: (effects, id) => {
    fetch(url, {
      method: "POST",
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        id: id
      })
    }).then(resp => {
      // response: { code: 200, result: 1}
      // do not change state here
      return resp
    })
  }
}

Use it:

effects.commentVote("78907890").then(resp => {
  if (resp.result === 1) {
    alert("Comment vote success!")
  }
})

In this case, commentVote doesn't change state.
Promise.resolve returns an object.

export const getEffects = (hocState, effectDefs, parentEffects) => {
  const applyReducer = reducer => {
    const result = reducer ? reducer(hocState.state) : null;
    // In this case, reducer should be an object 
    // reducer = { code: 200, result: 1 }
    if (result) {
      hocState.setState(result);
    }

    return result;
  };

  const effects = Object.keys(effectDefs).reduce((memo, effectKey) => {
    const effectFn = effectDefs[effectKey];

    memo[effectKey] = (...args) => Promise.resolve()
      .then(() => effectFn(effects, ...args))
      .then(applyReducer);

    return memo;
  }, Object.assign({}, parentEffects));

  return effects;
};

Clarify integration with class components and lifecycle methods

The idea of deferring state management to freactal is solid but as far as I can tell, users will still need to use class components if they want to trigger effects in lifecycle methods, and the README seems to imply that you can always use SFCs because freactal is orchestrating state, but that feels slightly misleading since React provides more than just state management APIs

Maybe add an example uses a stateless class component triggering effects in lifecycle methods to make it clear that stateless doesn't always mean functional components?

Access current state in effect

Hi,

Is there a way to access the current state from inside an effect ?
My use case is a saveToRemoteStuff effect that would take a computed value from the state, send it with a POST request and then, when the POST succeed update the state with { dataSaved: true } (or something like this...)
The problem is that I don't have access to the state in my effect ๐Ÿ˜ข

computed: {
  dataToSave: ({ ... }) => (...)
},
effects: {
  saveToRemoteStuff: () => {
    return save(/* Can't access dataToSave here :/  */)
      .then(() => mergeIntoState({ dataSaved: true }))
}

My solution for now is to get computed value in the component and then pass it to the effect but it feels wrong.

computed: {
  dataToSave: ({ ... }) => (...)
},
effects: {
  saveToRemoteStuff: (effects, dataToSave) => save(dataToSave)
      .then(() => mergeIntoState({ dataSaved: true }))
}

Is there any better way to do this kind of things ?
Ask me if you need more details :)

Etienne.

Add documentation to use with socket.io

I did not understand from examples, how can I change the state of stateless component with socket.io

Currently my component's state heavily depends on data arrived from socket.io.

I see that you solved fetch-like pull requests, but how can I set state on push-like socket messages?

Right now I have stateful HOC with lifecycle.

I'm making socket initialization on componentDidMount, saving socket to redux store if componentWillUnmount to reuse socket connection on repeated mount. It feels like I need to keep my HOC components stateful, but how can I inject Freactal state from HOC component's lifecycle?

BTW for sure your lib is straight to the point replacement to redux. Thank you very much for your creative mindset!

Question: calling an effect with updated state

so i'm trying to have two different provideStates for pagination, one that handles the pagination state, and one that does the fetching.

const withFetching = provideState({
  initialState: () => {
    return {
      entities: [],
    };
  },
  effects: {
    fetchItems: (effects, params) =>
      state => {
        // TODO: use { page , pageSize } from params
        return fetch('/things')
          .then(res => res.json())
          .then(({things}) => state => ({...state, entities: things}));
      },
  },
});

const justPagination = provideState({
  initialState: () => {
    return {
      page: 1,
      pageSize: 10,
    };
  },
  effects: {
    nextPage: effects => {
      return state => {
        const nextState = {...state, page: page + 1};
        return effects.fetchItems(nextState).then(() => nextState);
      };
    },
  },
});

const Container = withFetching(justPagination(YourComponent));

This doesn't work, but I'd like to do something like that. Any suggestions?

Subscribing to state changes

I am wondering if there is a plan to add a subscription or side effects api. The use case would be to execute functions on state change outside of component rendering. Example: syncing with local storage.

Can't get the current state new value after effect

I have read some of the issues posted here but can't seems to understand it clearly so I decided to create it myself.
Here's my code

<Form onSubmit={_handleSearching()}>
  <Form.Input
      type="text"
      id="barcode"
      icon="search"
      placeholder="Search barcode..."
   />
</Form>

Current state value will appear here and will update each form submission

<Step
    icon="inbox"
    title={"Indibox : " + state.indibar}
    description="date processed: "
 />

However getting the state a value is behind like this doing a console.log

    const _handleSearching = event => {
       event.preventDefault();
       const barcode = document.getElementById("barcode").value; //Z09J43H
    
      effects.readBarcode(barcode);
      console.log(state.indibar);
    };

My state wrapper

const stateWrapperIndibox = provideState({
  initialState: () => ({ indibar: "val" }),
  effects: {
    readBarcode: (effects, newVal) => state =>
      Object.assign({}, state, { indibar: newVal })
  }
});

Thanks

Example app Error: Cannot find module './lib/server'

Trying to test out the example app but npm start returns:

> [email protected] start /Users/charlesdu/src/rails/freactal/example
> NODE_ENV=development babel-node ./src/server

module.js:472
    throw err;
    ^

Error: Cannot find module './lib/server'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/charlesdu/src/rails/freactal/server.js:1:18)
    at Module._compile (module.js:571:32)
    at loader (/Users/charlesdu/src/rails/freactal/example/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/charlesdu/src/rails/freactal/example/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)

seems it is looking to load a module ./lib/server from ~/freactal/server.js but there is no /lib directory there?

npm run check fails on local

I'm using node v6.11.0 and npm 3.10.10

Here is the console output:

> [email protected] test /Users/XXX/freactal
> mocha spec/

/Users/XXX/freactal/spec/integration/nested-state-injection.spec.js:63
  it("children are updated when intermediate state injections are present", async function () {
                                                                            ^^^^^
SyntaxError: missing ) after argument list
    at createScript (vm.js:56:10)
    at Object.runInThisContext (vm.js:97:10)
    at Module._compile (module.js:542:28)
    at loader (/Users/XXX/freactal/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/XXX/freactal/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at fs.readdirSync.forEach.filename (/Users/XXX/freactal/spec/index.js:50:5)
    at Array.forEach (native)
    at recursiveRequire (/Users/XXX/freactal/spec/index.js:45:69)
    at Suite.describe (/Users/XXX/freactal/spec/index.js:48:30)
    at Object.create (/Users/XXX/freactal/node_modules/mocha/lib/interfaces/common.js:114:19)
    at context.describe.context.context (/Users/XXX/freactal/node_modules/mocha/lib/interfaces/bdd.js:44:27)
    at fs.readdirSync.forEach.filename (/Users/XXX/freactal/spec/index.js:48:5)
    at Array.forEach (native)
    at recursiveRequire (/Users/XXX/freactal/spec/index.js:45:69)
    at Object.<anonymous> (/Users/XXX/freactal/spec/index.js:54:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at /Users/XXX/freactal/node_modules/mocha/lib/mocha.js:230:27
    at Array.forEach (native)
    at Mocha.loadFiles (/Users/XXX/freactal/node_modules/mocha/lib/mocha.js:227:14)
    at Mocha.run (/Users/XXX/freactal/node_modules/mocha/lib/mocha.js:495:10)
    at Object.<anonymous> (/Users/XXX/freactal/node_modules/mocha/bin/_mocha:469:18)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:389:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:504:3

npm ERR! Darwin 15.6.0
npm ERR! argv "/Users/XXX/.nvm/versions/node/v6.11.0/bin/node" "/Users/XXX/.nvm/versions/node/v6.11.0/bin/npm" "run" "test"
npm ERR! node v6.11.0
npm ERR! npm  v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] test: `mocha spec/`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] test script 'mocha spec/'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the freactal package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     mocha spec/
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs freactal
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls freactal
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/XXX/freactal/npm-debug.log

npm ERR! Darwin 15.6.0
npm ERR! argv "/Users/XXX/.nvm/versions/node/v6.11.0/bin/node" "/Users/XXX/.nvm/versions/node/v6.11.0/bin/npm" "run" "check"
npm ERR! node v6.11.0
npm ERR! npm  v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] check: `npm run lint && npm run test`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] check script 'npm run lint && npm run test'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the freactal package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     npm run lint && npm run test
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs freactal
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls freactal
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /Users/XXX/freactal/npm-debug.log

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.