GithubHelp home page GithubHelp logo

delphinemillet / myrtille Goto Github PK

View Code? Open in Web Editor NEW

This project forked from fabienjuif/myrtille

0.0 1.0 0.0 25 KB

An immutable (but feeling mutable) one-way state manager without reducers

License: MIT License

JavaScript 100.00%

myrtille's Introduction

@fabienjuif/myrtille

An immutable (but feeling mutable) one-way state manager without reducers

npm npm bundle size

Features

  • ๐Ÿ”„ One-way state manager: your store is the single source of truth
  • ๐Ÿ’Ž Immutable but feels mutable
  • โ›๏ธ Hackable
  • ๐Ÿ’ก Based on events (actions)
  • ๐Ÿ“– Compatible with redux-devtools

Inspirations

The goal

The goal is to have a simple state manager, without behind strictely related to single UI library (like react or vue). The Redux pattern, having a one-way state management is a good pattern but Redux suffer from boilerplate, and once you add middleware you don't have clear separation of concerns. Myrtille tries to fix this drawbacks by using immer under the hood and by merging "reducers" and "reactions" in one place: listeners.

We also want to make sure your UI component tree is optimized and only refreshes when needed, that's why you can give a path to subscribers, you can make sure your component tree will be refreshed only when this path updates.

One of the last goal that Myrtille aims at is to let the developper doing whatever he wants with this library, that's why the store is always given and usable inside your callbacks, hack-it!

Installation

  • npm install --save @fabienjuif/myrtille
  • yarn add @fabienjuif/myrtille
  • pnpm install --save @fabienjuif/myrtille

API

  • createStore(initialState: Object) -> Store
    • create a store with the given initial state
    • eg: const store = createStore({ todos: [] })
  • Store.setState(newState: Object) -> void
    • set state to the given one and triggers listeners
  • Store.getState() -> State
    • get the current state.
  • Store.mutate((state: State) -> void): void
    • register a mutation, the currentState given in callback HAVE TO be muted, this is myrtille (via immer) that make sure this is done in an immutable way!
    • eg: store.mutate(state => { state.todos.push({ id: 2, label: 'new' }) })
  • Store.dispatch(action: String | Object) -> void
    • dispatch an action that listeners can register on, if the action is a string, the action is created by myrtille to follow the standard rule: { type: $yourString }
    • eg: store.dispatch('FETCH_TODOS')
    • eg: store.dispatch({ type: 'ADD_TODO', payload: { id: 2, label: 'new' }})
  • Store.addListener(action: String | Action | Function, callback: Function((store: Store, action: Action) -> void) | void) -> Function
    • add a listener to the store, a listener listen to an action, when this action is dispatched, the registered callback is called.
    • you can set your callback at first argument, in which it will be called for every actions dispatched.
    • you can play with the store in the given callback (dispatch new action, register mutations, etc)
    • calling the returned function will remove your callback
    • eg: take a look at listeners examples
  • Store.subscribe(path: String | Function, callback: Function(store: Store, oldState: State, action: Action) | void) -> Function
    • subcribe to state mutations at given path. The registered callback is called whenever the store as muted at given path.
    • you can set your callback at first argument, in which it will be called for every mutations
    • you can play with the store in the given callback (dispatch new action, register mutations, etc) but prefer using listeners and dispatching actions.
    • caling the returned function will unsubscribe your callback
  • Store.contexts: Object
    • used to retrieves some informations from your callbacks given in addListener and subscribe
    • eg: store.contexts.firebase = require('firebase/app')

Listeners examples

Async and mutation

  • Listen to an action that look like { type: 'FETCH_TODOS' }
  • Fetch todos
  • Set todos in store
const store = createStore({ todos: [] })
store.subscribe((store) => { console.log('new state!', store.getState()) })

// the listener to focus on
store.addListener('FETCH_TODOS', async (store) => {
  const todos = await (await fetch('https://my-api/todos')).json()
  store.mutate(state => {
    state.todos = todos
  })
})

// dispatch the listened action
store.dispatch('FETCH_TODOS')

retrieve action informations

  • Listen to ADD_TODO action that can be dispatched by a click from the UI)
  • Add a new todo with information given in the action's payload
const store = createStore({ todos: [] })
store.subscribe((store) => { console.log('new state!', store.getState()) })

// the listener to focus on
store.addListener('ADD_TODO', (store, action) => {
  store.mutate(state => {
    state.todos.push(action.payload)
  })
})

// dispatch the listened action
store.dispatch({ type: 'ADD_TODO', payload: { id: 2, label: 'new' } })

dispatch in a listener

  • Listen to @@ui/CLEAR_TODOS (that can be dispatched by a click from the UI)
  • React by calling CLEAR_TODOS if todos are not already empty
const store = createStore({ todos: [{ id: 1, label: 'finish the documentation' }] })
store.addListener((store, oldState, action) => { console.log('new action is dispatched!', action) })
store.addListener('CLEAR_TODOS', store => { store.mutate(state => { state.todos = [] }) })

// the listener to focus on
store.addListener({ type: '@@ui/CLEAR_TODOS' }, store => {
  if (store.getState().todos && store.getState().todos.length > 0) {
    store.dispatch('CLEAR_TODOS')
  }
})

// dispatch the listened action
store.dispatch('@@ui/CLEAR_TODOS')

Bindings

React

API

  • createStore(initialState: Object) -> Store: Please look at API.
  • Context: React.Context:
  • provider(store: Store) -> Function(React.Component) -> React.Component
  • useActions(actions: [](String | Function)) -> Function[]
  • useListeners(listeners: [][(String | Action), Function]) -> void
  • useStoreState(path: String | void) -> Any

myrtille's People

Contributors

fabienjuif avatar

Watchers

James Cloos avatar

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.