rootz
Rootz is JavaScript library for maintaining appliction state
Last updated 6 months ago by trishanthnaidu .
ISC · Repository · Bugs · Original npm · Tarball · package.json
$ cnpm install rootz 
SYNC missed versions from official npm registry.

Redux Logo

Rootz, is an open source JavaScript Library for maintaining application state.

It makes it easy to manage the state of your application. Another way of looking at this is, it helps you manage the data you display and how you respond to user actions. It helps you to view your application state as a whole at any point during application run. This makes it possible for us to monitor changes happening at the component level.

Rootz, helps you write applications with complete hold over its state. It also provides handler functions to manage your app state.

You can use Rootz with any frontend JavaScript library or framework. It helps with state management for all kind of JavaScript applications.

Note: We are currently planning a rewrite of Rootz docs.

Getting to know more…

To implement Rootz, basic understanding of JavaScript would do just fine. Just think of it as a root of a plant (your app).

Plant gets all the vital nutrients through its roots. Similarly, Rootz provides access to the entire application state through a simple getter/setter functions.

There are three key elements which one needs to be aware of for implementing Rootz.

Radicle

  • Represents the initial state of your application.
  • Is a JSON object.

Root

  • Represents the current state of you application
  • Is the only source of truth
  • Can only be accessed through the Root handlers
  • Is a JSON object

Handlers

  • Methods which helps you access Root.

Note: Handlers are described below in More About Handlers section.

The Three Principles

Rootz can be decribed by three fundamental principles:

Application’s current state should be true to the Root.

The state of your whole application is stored in a single tree, the Root. This makes it easy to maintain state in multiple component applications.

Root should only be accessed through the Handlers.

The only way to change the application state is through the Handlers.

Application with only one Root.

An Application should only consist of a single Root object.

More About Handlers...

Lets have a look at the Handlers in detail.

Note: We need to know about handlers before we proceed with the Implementation of Rootz.

appState

Handler object which holds set of functions to manage data stored in Root.

appState helps you store or retrieve application state variables. You can store strings, arrays, objects, functions through a simple get and set methods.

Note: A good practice would be to store functions in appMethods handler.

get

Retrieves data stored in Root.

syntax
/*
* @param: <branch-name>
* @type: string
*/

appState.get(<branch-name>);

branch-name, is used to represent the branch of Root in which the data is stored.

set

Stores data in Root.

syntax
/*
* @param-01: <branch-name>
* @type: string
* 
* @param-02: data
* @type: any
*/

appState.set(<branch-name>, data);

data, represents the data to be stored in Root by the name branch-name.

observe

Observes data stored in Root.

syntax
/*
* @param: <branch-name>
* @type: string
* 
* @param-02: callback
* @type: function
*/

appState.observe(<branch-name>, callback);

observe is used to execute a function when a branch is updated.

Once an observe is set on a branch, the callback function would be executed, whenever the branch is set with an updated value.

appMethods

Handler object which holds set of functions to manage functions stored in Root.

get

Retrieves functions stored in Root.

syntax
/*
* @param: <branch-name>
* @type: string
*/

appMethods.get(<branch-name>);

branch-name, is used to represent the branch of Root in which the function is stored.

set

Stores functions in Root.

syntax
/*
* @param-01: <branch-name>
* @type: string
* 
* @param-02: func
* @type: function
*/

appMethods.set(<branch-name>, func);

func, represents the function to be stored in Root by the name branch-name.

Getting Started…

Rootz, is a very simple framework to implement and use. Its simplicity of usage is its key strength

Installation

To install the stable version:

npm install —-save rootz

This assumes you are using npm as your package manager.

Complementary Packages

To use Rootz with React, most likely you would also require React Bindings.

npm install —-save react-rootz

Once all the dependencies are installed, we are all set to use Rootz. Let’s proceed with it’s implementation.

Implementation

Let us help you walk through the process of creating a simple Todo App.

We have used create-react-app to create a simple application, and it’s implementation proceeds with the same example.

Note: We will be using React application to demonstrate an example for implementing Rootz.

Folder Structure

todoApp
├── node_modules
├── public
├── src
│    │  
│    ├── actions
│    │      │
│    │      ├── addTodo.js
│    │      ├── todoFilter.js
│    │      ├── todoList.js
│    │      ├── index.js
│    │      
│    ├── components
│    │      │
│    │      ├── addTodo.js
│    │      ├── todoFilter.js
│    │      ├── todoList.js
│    │      
│    ├── constants.js
│    ├── index.js
│    ├── radicle.js
│    ├── todo.js
│    ├── todoStyles.css
│
├── .gitignore
├── package.json
├── package-lock.json

We would be following the above folder structure.

Note: The above folder structure is different from the one mentioned in the git repo. In git repo we have an additional folder named "example" inside ./src. While the logic and the working of the app remains the same.

To create a simple react app run the follwoing command:

npx create-react-app todoApp

This assumes you have npm as your package manager and have installed create-react-app.

Import createRoot from rootz to your index.js or any root file.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import serviceWorker from './serviceWorker';
import TodoApp from './todo';
import { createRoot } from 'rootz';
import Radicle from './radicle';

const rootz = new createRoot(Radicle);

ReactDOM.render(<TodoApp />, document.getElementById('root'));
serviceWorker.unregister();

createRoot will create Root, an application state from Radicle which can then be accessed through the appState handler.

Note: At this point the Root would consist of Radicle, as its initial state.

Let us design a Radicle, initial state structure.

radicle.js

import { todoFilter } from './constants';

const radicle = {
    "viewFilter": todoFilter.SHOW_ACTIVE,
    "todos": []
}

export default radicle; 

We consider two properties as Radicle of our Todo app

viewFilter, represents whether the todo is completed or not. todos, represents the actual array of todos.

constants.js

const todoFilter = {
    "SHOW_ALL": "SHOW_ALL",
    "SHOW_COMPLETED": "SHOW_COMPLETED",
    "SHOW_ACTIVE": "SHOW_ACTIVE"
}

export { todoFilter }

Currently we are considering three basic todo filters.

Let's quickly jump to the TodoApp in ./todo.js

todo.js

import React from 'react';
import AddTodo from './components/addTodo';
import TodoFilter from './components/todoFilter';
import TodoList from './components/todoList';
import './todoStyles.css';

class TodoApp extends React.Component {
    render() {
        return (
            <div className="todo-app">
                <AddTodo />
                <TodoList />
                <TodoFilter />
            </div>
        );
    }
}

export default TodoApp

Here the application is divided into three components, each having their individual actions.

Actions should be pure functions. We can add these actions inside their respective components as well. It is usually a good practise to keep the actions seperate from components.

Components

Components are resposible for fetching data and displaying it. Data comes from the Rootz and the business logic for managing the data is stored in Actions, of its respective components.

addTodo.js

import React from 'react';
import { addTodo } from '../actions';

let input;

class AddTodo extends React.Component {
    render() {
        return (
            <div className="add-todo">
                <input
                    type="text"
                    placeholder="Add a Todo"
                    ref={node => input = node}
                />
                <button
                    onClick={() => {
                        addTodo(input.value);
                        input.value = "";
                    }}
                >Add</button>
            </div>
        );
    }
}

export default AddTodo;

addTodo.js component takes input, as a todo from user and passes it to the addTodo function in ../actions.

todoFilter.js

import React from 'react';
import { todoFilter } from '../constants';
import { setTodoViewFilter } from '../actions';

class TodoFilter extends React.Component {
    render() {
        const todoFilters = Object.keys(todoFilter).map((filter, itr) => (
            <button
                key={itr}
                value={filter}
                onClick={setTodoViewFilter}
            >{filter}
            </button>
        ));
        return (
            <div className="todo-filter">
                {todoFilters}
            </div>
        );
    }
}

export default TodoFilter;

Similarily the todoFilter component displays filter buttons which helps user to select the type of todo they want to check (active, all or completed).

todoList.js

import React from 'react';
import { subscribe } from 'react-rootz';
import { 
    filteredTodoList,
    updateTodoFilter
} from '../actions';

class TodoList extends React.Component {
    constructor(props) {
        super(props);
        subscribe({
            name: "TodoList",
            scope: this,
            state: {}
        });
    }
    render() {
        const list = filteredTodoList();
        const todos = list.map((todo, itr) => (
            <li
                className={todo.completed ? "completed" : "active"}
                key={itr}
                onClick={updateTodoFilter}
            >{todo.name}
            </li>
        ));
        return (
            <ul className="todo-list">
                {todos}
            </ul>
        );
    }
}

export default TodoList;

The todoList component displays the todos initialised in Root (passed as a radicle while creating a Root in index.js).

As the implementation goes, this component needs to be refreshed once the todo is added and also when the user selects the todo filter.

We have used subscribe from react-rootz. Please checkout the benefits of using react-rootz with rootz in react applications.

Currently for a gist, subscribe here creates a subscription in name of TodoList with an empty state. Once a component is subscribed it can then be published with an updated state. In this example we would not use the inter-component (IC) rootz state. Rather we would simply store and retrieve data from the Root.

Note: We have used the react-rootz bindings for react app. This helps to utilise rootz with its additional bindings provided specially for react applications. For more details kindly check the react-rootz github page.

Note: Just not to be confused between IC state and Root, the IC state uses clever implementation of the Root for maintianing each component state. IC state may look like it is another form of application state. Rather, it uses Root as its core state. It is just a functionality which helps in managing inter component state with ease and reduced complexity.

Note: To know more about the difference between the IC state and Root, kindly check the react-rootz github page.

Actions

index.js

export { addTodo } from './addTodo';
export { setTodoViewFilter } from './todoFilter';
export {
    filteredTodoList,
    updateTodoFilter
} from './todoList';


addTodo.js

import { appState } from 'rootz';
import { publish } from 'react-rootz';

const addTodo = function (name) {
    let todos = appState.get("todos");
    todos = [...todos, {
        completed: false,
        name
    }];
    appState.set("todos", todos);
    publish("$TodoList");
}

export { addTodo }

The addTodo action gets the todos from the Root passed through Radicle. And sets the updated todos array in Root.

Note: Here publish, calls the TodoList component. This re-renders the TodoList component which takes the updated todos from the Root and displays the newly added todos depending upon the viewFilter selected.

todoFilter.js

import { appState } from 'rootz';
import { publish } from 'react-rootz';

const setTodoViewFilter = function (evt) {
    appState.set("viewFilter", evt.target.textContent);
    publish("$TodoList");
}

export { setTodoViewFilter };

Similarly the todoFilter sets the viewFilter in Root and publish the TodoList component.

todoList.js

import { appState } from 'rootz';
import { publish } from 'react-rootz';
import { todoFilter } from '../constants';

const filteredTodoList = function () {
    const todos = appState.get("todos");
    switch (appState.get("viewFilter")) {
        case todoFilter.SHOW_ACTIVE: {
            return todos.filter(todo => !todo.completed);
        }
        case todoFilter.SHOW_ALL: {
            return todos;
        }
        case todoFilter.SHOW_COMPLETED: {
            return todos.filter(todo => todo.completed);
        }
        default:
            return [];
    }
}

const updateTodoFilter = function (evt) {
    const todos = appState.get("todos");
    todos.filter(
        todo => todo.name === evt.target.textContent
    )[0].completed = true;
    appState.set("todos", todos);
    publish("$TodoList");
}

export { filteredTodoList, updateTodoFilter };

Now this part of the code shouldn't come as a surprise, where filteredTodoList returns the filtered list depends upon the selected viewFilter and the updateTodoFilter updates the todos with its completed status. And publish the TodoList component.

Examples

Currently we have added a simple todoApp as an example in the above git repo.

Note: More examples are on the way...

Thanks

To all those who have inspired me to come up with a new JavaScript state management tool.

Key Inspiration

Is my daughter, it came across as a surprise how my eleven month old baby tried to dump all her toys in a bucket and removed only those she needed to play with. She dumped all her smaller toys in a small buckets where the larger toys were dumped in a larger bucket.

This struck me, as at the same moment I was trying to develop an application in react which needed help in its state management. We struggled with Redux for the first couple of days, which made me think about an comparatively easier implementation for managing our application state.

This doesn't mention that Redux is complex or any negative thoughts towards them. Redux is a fantastic tool. Redux has a different way of implementation, where Rootz is different in its own way.

These two moments combined as an inspiration for Rootz.

But Why Rootz?

I like plantation, I sometimes spend my sunday mornings planting plants. And many a times I have planted part of roots of other plants to grow into a new plant. Just as in i need those plants in my gallery.

Rootz is similar, we grow the entire application Root with just a radicle.

License

ISC

Current Tags

  • 0.2.10                                ...           latest (6 months ago)

31 Versions

  • 0.2.10                                ...           6 months ago
  • 0.2.9                                ...           6 months ago
  • 0.2.8                                ...           6 months ago
  • 0.2.7                                ...           6 months ago
  • 0.2.6                                ...           6 months ago
  • 0.2.5                                ...           6 months ago
  • 0.2.4                                ...           6 months ago
  • 0.2.3                                ...           6 months ago
  • 0.2.2                                ...           6 months ago
  • 0.2.1                                ...           6 months ago
  • 0.2.0                                ...           6 months ago
  • 1.0.0                                ...           6 months ago
  • 0.0.8                                ...           6 months ago
  • 0.0.7                                ...           6 months ago
  • 0.0.6                                ...           6 months ago
  • 0.0.5                                ...           6 months ago
  • 0.0.4                                ...           6 months ago
  • 0.0.3                                ...           6 months ago
  • 0.0.2                                ...           6 months ago
  • 0.0.1                                ...           6 months ago
  • 0.1.10                                ...           6 months ago
  • 0.1.9                                ...           6 months ago
  • 0.1.8                                ...           6 months ago
  • 0.1.7                                ...           6 months ago
  • 0.1.6                                ...           6 months ago
  • 0.1.5                                ...           6 months ago
  • 0.1.4                                ...           6 months ago
  • 0.1.3                                ...           6 months ago
  • 0.1.2                                ...           6 months ago
  • 0.1.1                                ...           6 months ago
  • 0.1.0                                ...           6 months ago
Maintainers (1)
Downloads
Today 0
This Week 0
This Month 35
Last Day 0
Last Week 0
Last Month 5
Dependencies (0)
None
Dev Dependencies (0)
None
Dependents (1)

Copyright 2014 - 2016 © taobao.org |