react-hookstore
Advanced tools
Comparing version 1.0.8 to 1.1.0
@@ -110,2 +110,3 @@ (function webpackUniversalModuleDefinition(root, factory) { | ||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createStore", function() { return createStore; }); | ||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getStoreByName", function() { return getStoreByName; }); | ||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "useStore", function() { return useStore; }); | ||
@@ -124,3 +125,5 @@ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var stores = {}; | ||
@@ -131,8 +134,23 @@ | ||
}; | ||
var StoreInterface = function StoreInterface(name, store, useReducer) { | ||
_classCallCheck(this, StoreInterface); | ||
this.name = name; | ||
useReducer ? this.dispatch = store.setState : this.setState = store.setState; | ||
this.getState = function () { | ||
return store.state; | ||
}; | ||
}; | ||
function getStoreByIdentifier(identifier) { | ||
var name = identifier instanceof StoreInterface ? identifier.name : identifier; | ||
return stores[name]; | ||
} | ||
/** | ||
* Creates a new store | ||
* @param {Object} config - An object containing the store setup | ||
* @param {*} config.state [{}] - The store initial state. It can be of any type. | ||
* @param {String} config.name ['store'] - The store namespace. not required if you're not using multiple stores within the same app. | ||
* @callback confg.reducer [null] | ||
* @param {String} name - The store namespace. not required if you're not using multiple stores within the same app. | ||
* @param {*} state [{}] - The store initial state. It can be of any type. | ||
* @callback reducer [null] | ||
*/ | ||
@@ -142,14 +160,14 @@ | ||
* | ||
* @param {config.reducer} prevState, action - The reducer handler. Optional. | ||
* @param {reducer} prevState, action - The reducer handler. Optional. | ||
*/ | ||
function createStore(_ref) { | ||
var _ref$state = _ref.state, | ||
state = _ref$state === void 0 ? {} : _ref$state, | ||
_ref$name = _ref.name, | ||
name = _ref$name === void 0 ? 'store' : _ref$name, | ||
_ref$reducer = _ref.reducer, | ||
reducer = _ref$reducer === void 0 ? defaultReducer : _ref$reducer; | ||
function createStore(name) { | ||
var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var reducer = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultReducer; | ||
if (typeof name !== 'string') { | ||
throw 'store name must be a string'; | ||
} | ||
if (stores[name]) { | ||
@@ -173,13 +191,26 @@ throw 'store already exists'; | ||
store.setState = store.setState.bind(store); | ||
store.public = new StoreInterface(name, store, reducer !== defaultReducer); | ||
stores = Object.assign({}, stores, _defineProperty({}, name, store)); | ||
return store; | ||
return store.public; | ||
} | ||
/** | ||
* Returns a store instance based on its name | ||
* @param {String} name - The name of the wanted store | ||
*/ | ||
function getStoreByName(name) { | ||
try { | ||
return stores[name].public; | ||
} catch (e) { | ||
throw 'store does not exist'; | ||
} | ||
} | ||
/** | ||
* Returns a [ state, setState ] pair for the selected store. Can only be called within React Components | ||
* @param {String} name ['store'] - The namespace for the wanted store | ||
* @param {String|StoreInterface} identifier ['store'] - The identifier for the wanted store | ||
*/ | ||
function useStore() { | ||
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'store'; | ||
var store = stores[name]; | ||
var identifier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'store'; | ||
var store = getStoreByIdentifier(identifier); | ||
@@ -186,0 +217,0 @@ if (!store) { |
@@ -1,1 +0,1 @@ | ||
!function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e){t.exports=void 0},function(t,e,r){"use strict";r.r(e),r.d(e,"createStore",function(){return u}),r.d(e,"useStore",function(){return i});var n=r(0);let o={};const s=(t,e)=>e;function u({state:t={},name:e="store",reducer:r=s}){if(o[e])throw"store already exists";const n={state:t,reducer:r,setState(t){this.state=this.reducer(this.state,t),this.setters.forEach(t=>t(this.state))},setters:[]};return n.setState=n.setState.bind(n),o=Object.assign({},o,{[e]:n}),n}function i(t="store"){const e=o[t];if(!e)throw"store does not exist";const[r,s]=Object(n.useState)(e.state);return Object(n.useEffect)(()=>()=>{e.setters=e.setters.filter(t=>t!==s)},[]),e.setters.includes(s)||e.setters.push(s),[r,e.setState]}}]); | ||
!function(t){var e={};function r(n){if(e[n])return e[n].exports;var s=e[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,r),s.l=!0,s.exports}r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)r.d(n,s,function(e){return t[e]}.bind(null,s));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=1)}([function(t,e){t.exports=void 0},function(t,e,r){"use strict";r.r(e),r.d(e,"createStore",function(){return i}),r.d(e,"getStoreByName",function(){return c}),r.d(e,"useStore",function(){return a});var n=r(0);let s={};const o=(t,e)=>e;class u{constructor(t,e,r){this.name=t,r?this.dispatch=e.setState:this.setState=e.setState,this.getState=(()=>e.state)}}function i(t,e={},r=o){if("string"!=typeof t)throw"store name must be a string";if(s[t])throw"store already exists";const n={state:e,reducer:r,setState(t){this.state=this.reducer(this.state,t),this.setters.forEach(t=>t(this.state))},setters:[]};return n.setState=n.setState.bind(n),n.public=new u(t,n,r!==o),s=Object.assign({},s,{[t]:n}),n.public}function c(t){try{return s[t].public}catch(t){throw"store does not exist"}}function a(t="store"){const e=function(t){const e=t instanceof u?t.name:t;return s[e]}(t);if(!e)throw"store does not exist";const[r,o]=Object(n.useState)(e.state);return Object(n.useEffect)(()=>()=>{e.setters=e.setters.filter(t=>t!==o)},[]),e.setters.includes(o)||e.setters.push(o),[r,e.setState]}}]); |
{ | ||
"name": "react-hookstore", | ||
"version": "1.0.8", | ||
"version": "1.1.0", | ||
"description": "A state management library for react using the bleeding edge hooks feature", | ||
@@ -9,6 +9,9 @@ "main": "dist/react-hookstore.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"test": "jest", | ||
"build": "webpack --progress --config webpack.prod.config.js", | ||
"start": "webpack-dev-server --hot --reload --config webpack.dev.config.js" | ||
}, | ||
"jest": { | ||
"setupTestFrameworkScriptFile": "<rootDir>/tests-setup.js" | ||
}, | ||
"keywords": [ | ||
@@ -24,11 +27,17 @@ "react", | ||
"devDependencies": { | ||
"@babel/core": "^7.1.2", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/preset-env": "^7.1.0", | ||
"@babel/core": "^7.2.2", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.2.0", | ||
"@babel/preset-env": "^7.2.3", | ||
"@babel/preset-react": "^7.0.0", | ||
"@babel/preset-stage-0": "^7.0.0", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-jest": "^23.6.0", | ||
"babel-loader": "^8.0.4", | ||
"enzyme": "^3.8.0", | ||
"enzyme-adapter-react-16": "^1.7.1", | ||
"html-webpack-plugin": "^3.2.0", | ||
"jest": "^23.6.0", | ||
"react": "^16.7.0-alpha.0", | ||
"react-dom": "^16.7.0-alpha.0", | ||
"regenerator-runtime": "^0.13.1", | ||
"webpack": "^4.23.1", | ||
@@ -35,0 +44,0 @@ "webpack-cli": "^3.1.2", |
133
README.md
@@ -7,13 +7,28 @@ # React Hook Store | ||
# Table of Contents | ||
- [Installation](#installation) | ||
- Usage | ||
- [Basic](#usage_basic) | ||
- [Namespacing and referencing stores](#usage_namespace) | ||
- [Reducer powered stores](#usage_reducer) | ||
- API | ||
- [createStore](#api_createStore) | ||
- [getStoreByName](#api_getStoreByName) | ||
- [StoreInterface](#api_storeInterface) | ||
- [usStore](#api_useStore) | ||
- [Migrating from v1.0 to v1.1](#migration) | ||
> ⚠️ BREAKING CHANGES: Version 1.1 is not compatible with previous versions. It is easy to update your previous versions' code to work with it, though. [Click here](#migration) to know how. | ||
> ⚠️ Warning: hooks are not part of a stable React release yet, so use this library only for experiments | ||
## Installation | ||
## <a name="installation">Installation</a> | ||
You can install the lib through NPM or grab the files in the `dist` folder of this repository. | ||
`npm install --save react-hookstore` | ||
## Usage | ||
### Basic | ||
## <a name="usage">Usage</a> | ||
### <a name="usage_basic">Basic</a> | ||
This is the most basic implementation of the library. create a store with its initial state. | ||
Later, call `useStore` inside components to retrive its state and setState method. | ||
Later, call `useStore` inside components to retrieve its state and setState method. | ||
The value passed as the first argument to the setState method will be the new state. no reducer required (but you can use a reducer, see the advanced example down below). | ||
@@ -25,7 +40,7 @@ | ||
createStore({ state: 1 }); | ||
createStore('clickStore', 0); | ||
function StatefullHello() { | ||
// just use the useStore method to grab the state and the setState methods | ||
const [ state, setState ] = useStore(); | ||
const [ timesClicked, setClicks ] = useStore('clickStore'); | ||
@@ -35,4 +50,4 @@ return ( | ||
<h1>Hello, component!</h1> | ||
<h2>The button inside this component was clicked {state} times</h2> | ||
<button type="button" onClick={() => setState(state+1)}>Update</button> | ||
<h2>The button inside this component was clicked {timesClicked} times</h2> | ||
<button type="button" onClick={() => setClicks(timesClicked+1)}>Update</button> | ||
</div> | ||
@@ -54,4 +69,7 @@ ); | ||
### Advanced (namespaced and reducer-powered stores) | ||
We can delegate the state management to reducers (just like redux!) if we want, we can also namespace stores if we want to have more than one store per app. | ||
### <a name="usage_namespace">Namespacing and referencing stores</a> | ||
It is possible to create multiple stores in an app. | ||
A string name must be provided at a store creation when multiple stores are created. | ||
Stores can be referenced by using their instance that is returned by the createStore method, as well as using their name. | ||
```javascript | ||
@@ -61,4 +79,34 @@ import React from 'react'; | ||
const clickCount = createStore({ state: 1, name: 'clickCountStore'}); | ||
createStore({ state: 'John Doe', name: 'nameStore' }); | ||
// counter will start at 2 | ||
clickCount.setState(2); | ||
function StatefullHello() { | ||
// this line will reference a store by its instance | ||
const [ clicks, setClicks ] = useStore(clickCount); | ||
// this line will reference a store by its name | ||
const [ name ] = useStore('nameStore'); | ||
return ( | ||
<div> | ||
<h1>Hello, {name}!</h1> | ||
<h2>The button inside this component was clicked {clicks} times</h2> | ||
<button type="button" onClick={() => setClicks(clicks+1)}>Update</button> | ||
</div> | ||
); | ||
} | ||
``` | ||
Both methods can be used and mixed according to the needs, but we recomend using the instance identifiers. | ||
### <a name="usage_reducer">Reducer powered stores</a> | ||
We can delegate the state management to reducers (just like redux!) if we want. | ||
```javascript | ||
import React from 'react'; | ||
import { createStore, useStore } from 'react-hookstore'; | ||
// this one is more complex, it has a name and a reducer function | ||
createStore({ | ||
const todoListStore = createStore({ | ||
name: 'todoList', | ||
@@ -93,4 +141,3 @@ state: { | ||
function AddTodo() { | ||
// Grab the correct store by specifying its namespace | ||
const [ state: { todos }, dispatch ] = useStore('todoList'); | ||
const [ { todos }, dispatch ] = useStore(todoListStore); | ||
@@ -114,4 +161,3 @@ const onSubmit = (e) => { | ||
function TodoList() { | ||
// Grab the correct store by specifying its namespace | ||
const [ state: { todos }, dispatch ] = useStore('todoList'); | ||
const [ { todos }, dispatch ] = useStore(todoListStore); | ||
const deleteTodo = id => dispatch({ type: 'delete', payload: id }) | ||
@@ -130,14 +176,55 @@ return ( | ||
``` | ||
## API | ||
### `createStore(config={ state, name, reducer })` | ||
Creates a store to be used across the entire application. | ||
## Methods API | ||
### <a name="api_createStore">`createStore(name:String, state:*, reducer:Function):StoreInterface`</a> | ||
Creates a store to be used across the entire application. Returns a StoreInterface object. | ||
### Arguments | ||
#### `config.state:* = {}` | ||
#### `name:String` | ||
The namespace for your store, it can be used to identify the store across the application. | ||
#### `state:* = {}` | ||
The store's initial state. it can be any data type. defaults to an empty object. Optional | ||
#### `config.name:String = 'store'` | ||
The namespace for your store, it can be used to better identify the store across the application. Optional | ||
#### `config.reducer:Function = null` | ||
#### `reducer:Function = null` | ||
You can specify a reducer function to take care of state changes. the reducer functions receives two arguments, the previous state and the action that triggered the state update. the function must return a new state, if not, the new state will be `null`. Optional | ||
### `useStore(storeName='store')` | ||
### <a name="api_getStoreByName">`getStoreByName(name:String):StoreInterface`</a> | ||
Finds a store by its name and return its instance. | ||
### Arguments | ||
#### `name:String = 'store'` | ||
The name of the store. | ||
## Objects API | ||
### <a name="api_storeInterface">`StoreInterface`</a> | ||
The store instance that is returned by the createStore and getStoreByName methods. | ||
### Interface | ||
#### `name:String` | ||
The name of the store; | ||
#### `getState:Function():*` | ||
A method that returns the store's current state | ||
#### `setState:Function(*)` | ||
Sets the state of the store. works if the store does not use a reducer state handler. Otherwise, use `dispatch` | ||
#### `dispatch:Function(*)` | ||
Dispatchs whatever is passed into this function to the store. works if the store uses a reducer state handler. Otherwise, use `setState` | ||
## React API | ||
### <a name="api_useStore">`useStore(identifier:String|StoreInterface)`</a> | ||
A function that returns a pair with the current state and the handler method for the specified store. | ||
### Arguments | ||
#### Identifier:String|StoreInterface | ||
The store identifier. It can be either its string name or its StoreInterface instance returned by a createStore or getStoreByName method. | ||
# <a name="migration">Migrating from v1.0 to v1.1</a> | ||
- createStore now receives 3 arguments instead of an object with 3 properties. | ||
- the name argument is now required even if only one store is being used. | ||
```javascript | ||
// v0.1 | ||
createStore({state: 0}); | ||
createStore({ | ||
name: 'store', | ||
state: 0, | ||
reducer(state, action) { | ||
return state + action; | ||
} | ||
}) | ||
// v0.2 | ||
createStore('myStore', 0); | ||
createStore('store', 0, (state, value) => state + action); | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
29511
209
1
223
19