All Projects → jesseskinner → Hover

jesseskinner / Hover

Licence: mit
A very lightweight data store with action reducers and state change listeners.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Hover

nanoflux-fusion
Redux-like extension for Nanoflux
Stars: ✭ 15 (-84.54%)
Mutual labels:  flux, flux-architecture
AndroidFluxPractice
Android Flux Practice
Stars: ✭ 51 (-47.42%)
Mutual labels:  flux, flux-architecture
fluxy
Fluxy is a Flux architecture implementation written in Kotlin.
Stars: ✭ 25 (-74.23%)
Mutual labels:  flux, flux-architecture
Firedux
🔥 🐣 Firebase + Redux for ReactJS
Stars: ✭ 148 (+52.58%)
Mutual labels:  flux, flux-architecture
Fleur
A fully-typed, type inference and testing friendly Flux Framework
Stars: ✭ 74 (-23.71%)
Mutual labels:  flux, flux-architecture
Smitty
Tiny flux implementation built on mitt
Stars: ✭ 210 (+116.49%)
Mutual labels:  flux, flux-architecture
fluxiny
~1K implementation of flux architecture
Stars: ✭ 77 (-20.62%)
Mutual labels:  flux, flux-architecture
redux-reducer-async
Create redux reducers for async behaviors of multiple actions.
Stars: ✭ 14 (-85.57%)
Mutual labels:  flux, flux-architecture
mini-swift
Minimal Flux architecture written in Swift.
Stars: ✭ 40 (-58.76%)
Mutual labels:  flux, flux-architecture
Vuex-Alt
An alternative approach to Vuex helpers for accessing state, getters and actions that doesn't rely on string constants.
Stars: ✭ 15 (-84.54%)
Mutual labels:  flux, flux-architecture
Goes
Go Event Sourcing made easy
Stars: ✭ 144 (+48.45%)
Mutual labels:  flux, flux-architecture
Delorean
An Agnostic, Complete Flux Architecture Framework
Stars: ✭ 748 (+671.13%)
Mutual labels:  flux, flux-architecture
Fluxcapacitor
This is what makes the Flux design pattern possible.
Stars: ✭ 126 (+29.9%)
Mutual labels:  flux, flux-architecture
Nanoflux
A very lightweight and dependency-free Flux implementation
Stars: ✭ 56 (-42.27%)
Mutual labels:  flux, flux-architecture
react-workshops
Online react workshops
Stars: ✭ 36 (-62.89%)
Mutual labels:  flux, flux-architecture
universal-routed-flux-demo
The code in this repo is intended for people who want to get started building universal flux applications, with modern and exciting technologies such as Reactjs, React Router and es6.
Stars: ✭ 31 (-68.04%)
Mutual labels:  flux, flux-architecture
Fluxxan
Fluxxan is an Android implementation of the Flux Architecture that combines concepts from both Fluxxor and Redux.
Stars: ✭ 80 (-17.53%)
Mutual labels:  flux, flux-architecture
Starter React Flux
Generate your React PWA project with TypeScript or JavaScript
Stars: ✭ 65 (-32.99%)
Mutual labels:  flux
Speedux
Speedux is an opinionated library that makes Redux much more fun to use.
Stars: ✭ 82 (-15.46%)
Mutual labels:  flux
Matplotlib Chord Diagram
plot chord diagram with matplotlib
Stars: ✭ 60 (-38.14%)
Mutual labels:  flux


A very lightweight data store
with action reducers
and state change listeners.


NPM version Downloads Build Status Coverage Status Dependency status Dev Dependency status

Installation

You can use npm to install Hover, or download the raw file here.

For more information, check out the Concept, Usage, Documentation and FAQ below.

npm install hover

import Hover from 'hover'

Concept

Hover is a place to keep your state. You can pass in an initial state, but the only way to change the state afterwards is through action reducers you define.

The basic usage of Hover is:

// in store.js
import Hover from 'hover'

const actions = {
	increment: (state, amount) => state + amount
}

const initialState = 0

export default new Hover(actions, initialState)

// elsewhere
import store from './store'
const state = store.increment(2)

You can easily subscribe to state changes with Hover stores. You can pass a callback to the store. Your callback will be called immediately at first, and again whenever the state changes. Here's an example using vanilla DOM scripting to update the page:

function renderUserProfile (user) {
	if (user) {
		const root = document.getElementById('user-profile'),
			avatar = root.querySelector('.avatar'),
			name = root.querySelector('.name')

		// use the avatar url as an image source
		avatar.src = user.avatar

		// erase previous contents of name
		while (name.firstChild) {
			name.removeChild(name.firstChild)
		}

		// add name as a text node
		name.appendChild(document.createTextNode(user.name))
	}
}

userStore(renderUserProfile)

Here's an example rendering a React component:

function renderUserProfile (user) {
	ReactDOM.render(
		<UserProfile user={user} actions={userStore} />,
		document.getElementById('user-profile')
	)
}

userStore(renderUserProfile)

Usage

Here's how you might use Hover to keep track of clicks with a clickCounter.

const actions = {
	click: (state, text) => ({
		value: state.value + 1,
		log: state.log.concat(text)
	}),

	// go back to defaults
	reset: () => initialState
}

const initialState = 0

const clickCounter = new Hover(actions, initialState)

// listen to changes to the state
const unsubscribe = clickCounter(clickState =>
	document.write(JSON.stringify(clickState) + "<br>"
)

clickCounter.click('first')
clickCounter.click('second')

// reset back to zero
clickCounter.reset()

unsubscribe()

clickCounter.click("This won't show up")

If you run this example, you'll see this:

{"value":0,"log":[]}
{"value":1,"log":["first"]}
{"value":2,"log":["first","second"]}
{"value":0,"log":[]}

To see how Hover can fit into a larger app, with React and a router, check out the Hover TodoMVC.

Documentation

Hover is a function that takes an actions object and returns a store object.

Syntax

store = new Hover(actions[, initialState])

actions object

  • Any properties of the actions object will be exposed as methods on the returned store object.

  • If your state is a plain object, and you return plain objects from your actions, they will be shallow merged together.

  • Note that your actions will automatically receive state as the first parameter, followed by the arguments you pass in when calling it.

     // store is synchronous, actions are setters
     store = new Hover({
     	items: (state, items) => ({ items }),
     	error: (state, error) => ({ error })
     }, {})
    
     // load data asynchronously and call actions to change the state
     api.getItems((error, items) => {
     	if (error) {
     		return store.error(error)
     	}
    
     	store.items(items)
     })
    
     // listen to the state, and respond to it accordingly
     store(state => {
     	if (state.items) {
     		renderItems(state.items)
     	} else if (state.error) {
     		alert('Error loading items!')
     	}
     })
    

Return value

store = new Hover(actions[, initialState])

store object methods
  • store()

    • Returns the store's current state.
  • unsubscribe = store(function)

    • Adds a listener to the state of a store.

    • The listener callback will be called immediately, and again whenever the state changed.

    • Returns an unsubscribe function. Call it to stop listening to the state.

       unsubscribe = store(state => console.log(state))
      
       // stop listening
       unsubscribe()
      
  • state = store.action(arg0, arg1, ..., argN)

    • Calls an action handler on the store, passing through any arguments.

       store = new Hover({
       	add: (state, number) => state + number
       }, 0)
      
       result = store() // returns 0
       result = store.add(5) // returns 5
       result = store.add(4) // returns 9
       result = store() // returns 9
      

Hover.compose

Hover.compose takes a definition and creates a store, subscribing to any store members of the definition.

Hover.compose can take static variables, objects or arrays.

// create two stores
const scoreStore = new Hover({
    add: (state, score) => state + score
}, 0)
const healthStore = new Hover({
    hit: (state, amount) => state - amount
}, 100)

// compose the two stores into a single store
const gameStore = Hover.compose({
    score: scoreStore,

    // create an anonymous store to nest objects
    character: Hover.compose({
        health: healthStore
    })
})

// stores and actions can be accessed with the same structure
gameStore.score.add(2)

gameStore.character.health.hit(1)

You can also pass zero or more translate functions after your compose definition, to automatically translate or map the state every time it gets updated.

These translate functions will receive a state argument, and must return the resulting state.

// create stores to contain the active and completed todos
const activeTodoStore = Hover.compose(todoStore, todos =>
    todos.filter(todo => todo.completed === false)
)

const completedTodoStore = Hover.compose(todoStore, todos =>
    todos.filter(todo => todo.completed === true)
})

FAQ

Q: How does Hover handle asynchronous loading of data from an API?

There are three ways to achieve this. One way is to load the API outside of the store, and call actions to pass in the loading state, data and/or error as it arrives:

const store = new Hover({
	loading: (state, isLoading) => ({ isLoading }),
	data: (state, data) => ({ data }),
	error: (state, error) => ({ error })
})

store.loading(true)

getDataFromAPI(params, (error, data) => {
	if (error) {
		return store.error(error)
	}

	store.data(data)
})

Another way is to make API calls from inside your actions.

const store = new Hover({
	load: (state, params) => {
		getDataFromAPI(params, (error, data) =>
			store.done(error, data)
		)

		return { isLoading: true, error: null, data: null }
	},
	done: (state, error, data) => (
		{ isLoading: false, error, data }
	)
})

store.load(params)

Q: If Hover stores only have a single getter, how can I have something like getById?

If you have access to a list of items in the state, you can write code to search through the list. You could even have a function like this as a property of the store, before you export it, eg.

import Hover from 'hover'

const initialState = [{ id: 1, name: 'one' }, /* etc... */ }

const itemStore = new Hover({
	add: (list, item) => list.concat(item)
}, initialState)

// add a helper function to the store
itemStore.getById = id =>
	list.filter(item => item.id === id).pop()

// getAll
const items = itemStore()

// look up a specific item
const item = itemStore.getById(5)


Versioning

Hover follows semver versioning. So you can be sure that the API won't change until the next major version.

Testing

Clone the GitHub repository, run npm install, and then run npm test to run the tests. Hover has 100% test coverage.

Contributing

Feel free to fork this repository on GitHub, make some changes, and make a Pull Request.

You can also create an issue if you find a bug or want to request a feature.

Any comments and questions are very much welcome as well.

Author

Jesse Skinner @JesseSkinner

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].