stas-other-immutable

0.3.1 • Public • Published

A state management with promise middleware, immutable data and model normalization

RECOMMEND: Use stas with simple and seamless immutability support!

Features

  • Express-like and promise-based middlewares and routers, see Middleware and Router
  • Immutable state and operations, see Immutable State
  • Normalize the data by model

Example

// store.js
import { Store, Model } from 'stas-other-immutable';
import router from './router';

const models = [
  ['User', {
    posts: 'Post',
  }],
  ['Post', {
    author: 'User',
  }],
];

const store = new Store({ users: [] }, { models });
store.use(router);

module.exports = store;

// router.js
import createRouter from 'uni-router';
const router = createRouter();

router.all('/users/query', async (req, resp, next) => {
  const { store } = req,
    { User } = store.models,
    { offset, limit } = req.body;

  const result = await fetch('/api/users/query', { offset, limit });

  store.mutate((newState) => {
    const ids = User.merge(result);
    newState.set('users', ids);
  });
});

router.all('/users/:userId/posts/create', async (req, resp, next) => {
  const { store } = req,
    { User, Post } = store.models,
    { userId } = req.params,
    { title } = req.body;

  const result = await fetch(`/api/users/${userId}/posts/create`, { title });

  store.mutate((newState) => {
    const postId = Post.merge(result);
    const user = User.get(userId).set('posts', posts => posts.push(postId));
    store.User.set(userId, user);
  });
});

module.exports = router;

// UserListPage.js
import { PureComponent, PropTypes } from 'react';
import { connect } from 'react-stas';

class UserListPage extends PureComponent {
  static propTypes = {
    users: PropTypes.array.isRequired,
    dispatch: PropTypes.func.isRequired,
  }

  render() {
    const { users } = this.props;
    return (<ul>
      {users.map(user => <li>
        <span>{user.name}</span>
        <span>{user.posts.map(post => post.title).join(',')}</span>
      </li>)}
    </ul>);
  }
}

module.exports = connect(({ state, dispatch, props, store }) => {
  const { User, Post } = store.models;
  const userIds = state.get('users').toJSON();
  const users = User.mget(userIds).map((user) => {
    user = user.toJSON();
    user.posts = user.posts.map(postId => Post.get(postId).toJSON());
    return user;
  });
  return { users };
})(UserListPage);

// index.js
import ReactDom from 'react-dom';
import { Provider } from 'react-stas';
import store from './store';
import UserListPage from './UserListPage';

ReactDom.render(
  <Provider store={store}>
    <UserListPage />
  </Provider>,
  document.getElementById('app'),
);

Installation

yarn add stas react-stas uni-router -S

or if your'd like to use npm:

npm install stas react-stas uni-router -S

Middleware

store.use((req, resp, next)=>{})

Router

Like express router but with promise support. For detail see uni-router

router.use(pattern?: string, middleare)

Prefix match req.url with pattern

router.all(pattern?: string, middleare)

Exact match req.url with pattern

Immutable State

Use List, Map and Model to manipulate the state. For detail see immutable-state.

store.mutate(callback)

Start a new mutation operation.

.get(keysPath: array|string)

Get the value on the specific keys path.

.set(keysPath: array|string, value: json|function)

Set the value on the specific keys path. If passed function, the function must return the result value.

.toJSON() or .toJS()

Convert to plain json object

.keys()

Return the keys

.length or .size

Return the keys length

.filter()/.find()/.findKey()/.forEach()/.map()/.reduce()/

Like array corresponding methods, most with (value, key, thisArg)=>{} signature.

.remove(keyPath) or .delete(keyPath)

Remove the leaf key

.merge(strategy?: bool|function, input)

Merge the value with specific strategy.

.slice()/.findIndex()/.push()/.pop()/.unshift()/.shift()

Like array corresponding methods. List only.

Hot Reload(HMR)

Since react-native doesn't support module.hot.accept(path, callback) but module.hot.accept(callback), we have to use a function to export the store, then replace store's middlewares(routers) by utilizing closure.

import Store from 'stas';
import routers from './routers';

export default function createStore() {
  const store = new Store()
  store.use(routers);

  if (module.hot) {
    module.hot.accept(() => {
      const newRouters = require('./routers').default;
      store.clearMiddlewares();
      store.use(newRouters);
    });
  }
  return store;
}

Contributing

Checkout the CONTRIBUTING.md if you want to help

License

Licensed under MIT

Copyright (c) 2017 Tian Jian

Package Sidebar

Install

npm i stas-other-immutable

Weekly Downloads

0

Version

0.3.1

License

MIT

Last publish

Collaborators

  • tianjianchn