npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nanox

v0.2.4

Published

Minimal framework for small projects using React

Downloads

8

Readme

English | 日本語

Nanox

Nanox is a minimal framework for small projects using React.

It is intended to be used when you want to create a React application using some framework but you do not need to be as big as Redux.

The feeling of use is close to Hyperapp(v1).

flowchart

Feature

  • Low learning costs
  • Provides multiple state update methods depending on the purpose
  • Because views and actions are separated, it's easy to test each one alone.

Install

$ npm install nanox

Usage

STEP 1 - Create actions

First, create actions to use in child components.

const myActions = {
  // action name is 'increment'
  increment(count) {
    // return partial state that you want to update
    return {
      count: this.state.count + count
    };
  },

  // action name is 'decrement'
  decrement(count) {
    // you can return Promise Object that resolve partial state
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // resolve partial state that you want to update
        resolve({
          count: this.state.count - count
        });
      }, 1000);
    });
  }
};

export default myActions;

STEP 2 - Create child component

Create child component that uses the actions created in STEP1.

In the following example, the actions are received via props, but you may use Context instead.

const CounterComponent = ({ actions, count }) => {
  // execute action in click handler
  return (
    <div>
      <div>{count}</div>
      <button onClick={() => actions.increment(1)}>+1</button>
      <button onClick={() => actions.decrement(1)}>-1(delay 1s)</button>
      <button onClick={() => actions.increment(100)}>+100</button>
    </div>
  );
};

export default CounterComponent;

STEP 3 - Create Nanox container

Create Naxox container to manage actions and child components.

// import React
import React from 'react';
import ReactDOM from 'react-dom';

// import Nanox
import Nanox from 'nanox';

// import actions created in STEP 1
import myActions from './actions';

// import child component created in STEP 2
import CounterComponent from './counter';

// create container (inherit Nanox)
class MainContainer extends Nanox {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    // pass this.actions to child component props (not this.props.actions)
    return <CounterComponent actions={this.actions} {...this.state} />;
  }
}

STEP 4 - Mount the Nanox container

Mount the Nanox container created in STEP 3 to the DOM.

At this time, register the actions created in STEP 1 via props.

ReactDOM.render(
  // register actions that created at STEP 1
  <MainContainer actions={myActions} />,
  document.getElementById('app')
);

Examples

Example Demo

Spec of Action

If Action returns values, that must be partial state object or Promise Object.

:x: Bad: return number

const myActions = {
  foo(x, y, z) {
    return x + y + z;
  }
};

:heavy_check_mark: Good: return partial state

const myActions = {
  foo(x, y, z) {
    return {
      count: x + y + z
    };
  }
};

:heavy_check_mark: Good: return Promise Object (resolve partial state)

const myActions = {
  foo(x, y, z) {
    return new Promise((resolve, reject) => {
      resolve({
        count: x + y + z
      });
    });
  }
};

:heavy_check_mark: Good: return nothing (no effect on Nanox container)

const myActions = {
  foo(x, y, z) {
    console.log(x, y, z);
  }
}

Get the current state in actions

You can get the current state in Nanox container from this.state in the action.

class MainContainer extends Nanox {
  constructor (props) {
    super (props);
    // create state in Nanox container
    this.state = {
      count: 0,
      waiting: false
    };
  }
    .
    .
    .
}
const myActions = {
  increment (count) {
    // get the current state in the action
    const currentState = this.state; // => {
                                     //  count: 0,
                                     //  waiting: false
                                     //}
      .
      .
      .
  }
};
Note

Since this.state is a copy of the latest state of the Nanox container, changing this value directly has no effect on the state of the Nanox container.

Advanced Usage

Updating state by this.query()

You can also update the state by MongoDB-like query using this.query().

class MainContainer extends Nanox {
  constructor(props) {
    super(props);
    this.state = {
      // create state in Nanox container
      fruits: [ 'apple', 'banana', 'cherry' ]
    };
  },
    .
    .
    .
};
const myActions = {
  addLemon() {
    // call this.query() with $push command, and return functions result
    return this.query({
      fruits: {
        $push: [ 'lemon' ] // => will be [ 'apple', 'banana', 'cherry', 'lemon' ]
      }
    });
  },
    .
    .
    .
};

The available commands are here.

In addition to the above commands, you can also add custom commands.

ReactDOM.render(
  // register $increment command when mounting Nanox container
  <MainContainer
    actions={myActions}
    commands={{
      $increment: (value, target) => target + value
    }}
  />,
  document.getElementById('app')
);
const myActions = {
  increment() {
    // can use $increment command in action
    return this.query({
      // value = 1, target = this.state.count
      count: { $increment: 1 }
    });
  },
    .
    .
    .
};

See here for details on how to create custom commands.

Note

Direct specification of state value can not be mixed in this.query().

// Bad
return this.query({
  name: 'foo',
  history: { $push: [ 'change name' ] }
});

If you want to execute the direct specification of status value and query command simultaneously as above, use $set command instead of direct specification of status value.

// Good
return this.query({
  name: { $set: 'foo' },
  history: { $push: [ 'change name' ] }
});

Action chaining

Calling an action in child components returns a Promise object that resolves when the action is completed, so you can perform multiple actions in sequence.

It is used, for example, to display the indicator when performing long actions in sequence and to clear the indicator when it is completed.

And you can also catch errors that occur in actions using catch.

return (
  <button onClick={
    actions.loading(true)
    .then(() => actions.fetchFriends())
    .then(() => actions.sendMessage('hello'))
    .then(() => actions.loading(false))
    .catch(console.error);
  }>Say hello to my friends</button>
);

Pre-update hook

You can register a hook method(onSetState()) that will be executed just before the state is updated by the action.

If onSetState() process returns false, this state updating is aborted.

class MainContainer extends Nanox {
    .
    .
    .
  onSetState(data, type) {
    // data = partial state or update query that will apply to Nanox state
    // type = 'state' or 'query'
    if ( ... ) {
      // You can block applying action result to state by returning false at onSetState()
      return false;
    }
  }
    .
    .
    .
};
Note

Since the data that is the argument of onSetState() is a copy of the state part to be updated, changing this value directly will not change the updated contents.

How to use from TypeScript

see here.

License

MIT

© 2017-2019 ktty1220