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

@mozaikjs/core

v0.6.42

Published

Predictable state container for JavaScript apps

Downloads

50

Readme

Install

npm i @mozaikjs/core

or

yarn add @mozaikjs/core

Usage

import { types } from '@mozaikjs/core'

/*
 * types.model ➜ actions() ➜ create()
 */

/**
 * Step 1.
 * Declare node (like reducers or models)
 */
const router = types
  .model({
    history: types.array(types.string),
    path: types.string
  })
  .actions({
    push({ dispatch, state }, path) {
      dispatch({
        path,
        history: [...state().history, path]
      })
    },
    replace({ dispatch, state }, path) {
      const history = state().history
      history.splice(history.length - 1, 1, path)
      dispatch({
        path,
        history
      })
    }
  })

/**
 * Step 2.
 * Create instace & set default values
 */
const routerInstance = router.create({
  history: ['/'],
  path: '/'
})

/**
 * Step 3.
 * Call action
 */
routerInstance.push('/about')

/**
 * Step 5.
 * Get action results
 */
console.log(routerInstance.$getState())
// ➜ { history: ['/', '/about'], path: '/about' }

/**
 * Subscribe on notify
 */

routerInstance.$subscribe(({ state }) => console.log(state))
routerInstance.replace('/faq')
// ➜ { history:  ['/', '/faq'], path: '/faq' }

Get actual state

Mozaikjs use immutable state

For get actual state you get call $getState() on store instance. Inside actions and computed you can take state() method for get actual state.

import { types } from '@mozaikjs/core'

const root = types
  .model({
    status: types.string
  })
  .actions({
    async load({ dispatch, state }) {
      dispatch({ status: 'pending' })
      console.log(state().status) // ➜ 'pending'
      setTimeout(() => {
        dispatch({ status: 'done' })
        Promise.resolve()
      })
    }
  })
  .create({
    status: 'default'
  })

await root.load()
console.log(root.status) // ➜ 'default'  State don`t mutable
console.log(root.$getState().status) // ➜ 'done'  State updated

Runtime check types

Mozaikjs like Mobx State Tree check state when you change

| Type | Example | Description | | -------------------------------- | --------------------------------------------------- | --------------------------------------------------------- | | Primitives | | string | types.string | | | number | types.number | | | boolean | types.boolean | | | Date | types.date | Check is Date instance | | any | types.any | Use for only immutable data. Data do not reactive. If you use this type, mozaik can not build correct scheme for data and as a result data ceases be observable. | | Complex type | | | | maybe (Deprecated, use optional) | types.maybe(types.string) | Value can be empty (null or undefined) | | optional | types.optional(types.string, defaultValue?: string) | Value can be empty (null or undefined) with default value | | array | types.array(types.number) | Array of values | | enumeration | types.enumeration('admin', 'moderator') | Value can be one of enums | | custom | types.custom(types.number, (value) => value > 10) | You can write custom validator | | model | types.model(name, props) | |

Subscribe & notify

You have two ways to subscribe on notify.

  • chain method before create instances
  • method $subscribe on created instances
const commentModel = types
  .model('comment', {
    isLiked: types.boolean
  })
  .actions({
    toggleLike({ dispatch, state }) {
      dispatch({
        isLiked: !state().isLiked
      })
    }
  })

const fetcher = types
  .model({
    comments: types.array(commentModel)
  })
  .subscribe(console.log) // call after change state
  .create({
    comments: [
      {
        isLiked: false
      }
    ]
  })

fetcher.$subscribe(console.log)
fetcher.comments[0].$subscribe(console.log)

fetcher.comments[0].toggleLike() // Do toggle inner state

Compose nodes

import { types } from '@mozaikjs/core'

const resetModel = types.model({}).actions({
  reset({ dispatch, state }) {
    const newState = Object.keys(state()).reduce((acc, key) => {
      acc[key] = null
      return acc
    }, {})
    dispatch(newState)
    return newState
  }
})

const userNode = types
  .model({
    name: types.maybe(types.string),
    age: types.maybe(types.number)
  })
  .compose(resetModel)
  .create({
    name: 'Arthur',
    age: 24
  })

console.log(userNode.$getState()) // ➜ { name: 'Arthur', age: 24 }
userNode.reset()
console.log(userNode.$getState()) // ➜ { name: null, age: null }

Computed props

import { types } from '@mozaikjs/core'

const user = types
  .model({
    name: types.string,
    lastName: types.string
  })
  .actions({
    setName({ dispatch }, name) {
      dispatch({
        name
      })
    }
  })
  .computed({
    fullName({ state }) {
      return `${state().name} ${state().lastName}!`
    }
  })
  .create({
    name: 'Arthur',
    lastName: 'Test'
  })

console.log(user.$getState().fullName) // ➜ Arthur Test!

Shape models (modules)

import { types } from '@mozaikjs/core'

const userModel = types.model({ name: types.string })
const routerModel = types.model({ path: types.string }).actions({ push() {} })

const rootModel = types.model({
  router: routerModel,
  user: userModel
})

Catch errors

You can catch errors in actions. Use .catch chain method.

When error be catch you pass error context.

context

{
  name: string
  methodName: string
  error: Error
  store: {
  }
}
import { types } from '@mozaikjs/core'

const root = types
  .model({
    status: types.string
  })
  .actions({
    fetch() {
      throw new Error('test error')
    }
  })
  .catch(console.log)
  .create({
    status: 'done'
  })

root.fetch()

Dependency Injection

import { types } from '@mozaikjs/core'

const routerStore = types
  .model('router', {
    path: types.string
  })
  .create({
    path: '/'
  })

const fetcherModel = types
  .model({
    isLoading: types.boolean
  })
  .actions({
    fetch({ env }, path) {
      console.log(env) // ➜ { httpClient: {}, localStorage, routerStore }
      console.log(path) // ➜ /users
    }
  })
  .create(
    {
      isLoading: false
    },
    {
      routerStore, // You can pass other model and they be computed
      httpClient: {},
      localStorage: localStorage
    }
  )

console.log(fetcherModel.fetch('/users'))

Middlewares (Deprecated)

Use middleware you can control each dispatch state. Middleware chain call everytime when you call action. If middleware don't return value, state don`t change.

TODO:

  • Add async
  • Pass store instance
const toUpperCase = state => {
  return Object.keys(state).reduce((res, key) => {
    res[key] = state[key].toUpperCase()
    return res
  }, {})
}

const user = types
  .model({
    name: types.string
  })
  .actions({
    fetchUser({ dispatch }) {
      dispatch({ name: 'admin' })
    }
  })
  .use(toUpperCase)
  .use('fetchUser', toUpperCase) // Add middleware on specific action
  .create({
    name: ''
  })

user.fetchUser()
user.$getState() // ➜ { name: 'ADMIN' }

Plugins

const myPlugin = store => {
  // call after create store
  store.$subscribe(ctx => {
    // call after every mutation
    // ctx = { state: any, oldState: any, name: string, methodName: string }
  })
}
import { types } from '@mozaikjs/core'

const model = types
  .model({})
  .plugins(myPlugin) // Add plugins
  .create({})

TODO

  1. Add .named() method for model
  2. Make treeWalker for develop plugins
  3. Add new features for work with names
  4. Pass inside computed function only state without actions
  5. Add type for lazy load modules of tree
  6. Add hooks for adapters of React + Vue
    1. Data hooks useAction + useValue
    2. Network hooks useQuery + useMutation
  7. Make ability to parse default props to types .model('', { prop: 10 })
  8. Add great support for plugins
    1. Ability to append custom methods and getters
    2. Possibility integrate to model by chain methods
  9. Create few plugins
    1. Cache manager
    2. Redo/Undo
    3. Persist
    4. Logger
    5. Connector to Redux dev tools
  10. Add new Examples
  11. Make site