Biblioteca de gestión estatal progresiva de 1kb inspirada en Vuex.
Puede obtener esta biblioteca como un módulo Node.js disponible a través del registro NPM:
// With npm
$ npm install dragonbinder
// With yarn
$ yarn add dragonbinder O puede usarlo independiente en el navegador con: <script src="https://cdn.jsdelivr.net/npm/dragonbinder"></script>
const Dragonbinder = require ( 'dragonbinder' ) ;
const store = new Dragonbinder ( {
state : {
count : 0
} ,
mutations : {
increment ( state ) {
state . count ++
}
}
} ) ;
store . commit ( 'increment' ) ;
console . log ( store . state . count ) // -> 1Dragonbinder usa proxies para crear un estado como una "fuente única de verdad" que no se puede cambiar a menos que comete una mutación. Esto significa que no puede eliminar, modificar o agregar una propiedad directamente. Esto nos permite realizar un seguimiento de todos los cambios que hicimos en el estado.
Si no proporciona un estado inicial por parte de la propiedad state , Dragonbinder creará uno.
const store = new Dragonbinder ( {
state : {
count : 0
} ,
mutations : {
addProperty ( state , value ) {
state . hello = 'world' ;
} ,
modifyProperty ( state ) {
state . count ++
} ,
removeProperty ( state ) {
delete state . count ;
}
}
} ) ;
// This will throw errors
store . state . hello = 'world' ;
store . state . count ++ ;
delete state . count ;
// This will work as expected
store . commit ( 'addProperty' ) ;
store . commit ( 'modifyProperty' ) ;
store . commit ( 'removeProperty' ) ;Además, si desea evitar que los solteros reutilicen la definición de su tienda inicial, puede declarar su estado como una función de fábrica.
const myStoreDefinition = {
state ( ) {
return {
count : 1
}
} ,
mutations : {
increment ( state , payload ) {
state . count = state . count + payload ;
}
}
} ;
const store1 = new Dragonbinder ( myStoreDefinition ) ;
const store2 = new Dragonbinder ( myStoreDefinition ) ;
store1 . commit ( 'increment' , 5 ) ;
store2 . commit ( 'increment' , 3 ) ;
console . log ( store1 . state . count ) ; // -> 6
console . log ( store2 . state . count ) ; // -> 4Al igual que con Vue, con Dragonbinder puede crear getters para crear propiedades calculadas basadas en el estado. Este Getters recibirá el Estado como primer argumento y todos los demás Getters como segundo.
const store = new Dragonbinder ( {
state : {
todos : [
{
content : 'First' ,
completed : false
} ,
{
content : 'Second' ,
completed : true
}
]
} ,
getters : {
completed ( state ) {
return state . todos . filter ( item => item . completed ) ;
} ,
completedCount ( state , getters ) {
return getters . completed . length ;
}
}
} ) ;
console . log ( store . getters . completed ) ; // -> { content: 'Second', completed: true }
console . log ( store . getters . completedCount ) ; // -> 1Las mutaciones son la única forma de cambiar el estado y debe considerar los próximos puntos al diseñar mutaciones.
Object.freeze Disfruta para evitar cambios directos. Entonces, cuando está cambiando el estado usando una mutación, puede agregar, modificar o eliminar solo las propiedades de primer nivel, las propiedades de segundo nivel solo se leerán. const store = new Dragonbinder ( {
state : {
hello : {
name : 'John Doe'
}
} ,
mutations : {
changeNameError ( state , payload ) {
state . hello . name = payload ;
} ,
changeNameOk ( state , payload ) {
state . hello = { ... state . hello , name : payload } ;
} ,
changeNameTo ( state , ... args ) {
state . hello = { ... state . hello , name : args . join ( ' ' ) } ;
}
}
} ) ;
// This will throw an assign to read only property error
store . commit ( 'changeNameError' , 'Jane Doe' ) ;
// This will work as expected
store . commit ( 'changeNameOk' , 'Jane Doe' ) ;
// You can pass any number of arguments as payload
store . commit ( 'changeNameTo' , 'Jane' , 'Doe' ) ;Si necesita manejar las funciones de Async, debe usar acciones. Y las acciones siempre devolverán una promesa como resultado de llamarlos.
const store = new Dragonbinder ( {
state : {
count : 0
} ,
mutations : {
increment ( state ) {
state . count ++
}
} ,
actions : {
increment ( state ) {
return new Promise ( ( resolve ) => {
setTimeout ( ( ) => {
store . commit ( 'increment' ) ;
resolve ( ) ;
} , 1000 ) ;
} )
}
}
} ) ;
store . dispatch ( 'increment' ) . then ( ( ) => console . log ( store . state . count ) ) ; // -> 1 after one secondPuede registrar/no registrar devoluciones de llamada a los eventos.
const store = new Dragonbinder ( {
state : {
count : 0
} ,
mutations : {
increment ( state ) {
state . count ++
}
}
} ) ;
// Add a named listener
let namedListener = ( store , prop , newVal , oldVal ) => console . log ( `The property ${ prop } was changed from ${ oldVal } to ${ newVal } ` ) ;
store . on ( 'set' , namedListener ) ;
// Add an anonymous listener
let removeAnonymousListener = store . on ( 'set' , ( ) => console . log ( 'Anonymous listener triggered' ) ) ;
// Committing increment will trigger the listener
store . commit ( 'increment' ) ;
// $ The property count was changed from 0 to 1
// $ Anonymous listener triggered
// Remove a named listener
store . off ( 'set' , namedListener ) ;
// Remove an anonyous listener
removeAnonymousListener ( ) ;
// Committing increment will do nothing as the listeners are already removed
store . commit ( 'increment' ) ; Todos los eventos reciben la instancia de la tienda como el primer argumento.
| Nombre del evento | Se llama cuando | Argumentos recibidos por lugar |
|---|---|---|
| Addlistener | Se agrega un oyente de eventos | Nombre del evento | Oyente agregado |
| remolino | Se elimina un oyente de eventos | Nombre del evento | Oyente eliminado |
| colocar | Se agrega o modifica una propiedad del estado, también se activa cuando se registra un módulo | Nombre de la propiedad | Nuevo valor | Valor antiguo |
| borrar | Se elimina una propiedad del estado, también se activa cuando un módulo no está registrado | Nombre de la propiedad | Valor antiguo |
| estar de acuerdo con | Método de confirmación llamado y antes de aplicar la mutación | Nombre de mutación | (...) argumentos pasados a la mutación |
| comprometerse | Método de confirmación llamado y después de aplicar la mutación | Nombre de mutación | (...) argumentos pasados a la mutación |
| beforedispatch | Método de envío llamado y antes de aplicar la acción | Nombre de acción | (...) Argumentos pasados a la acción |
| despacho | Método de envío llamado y después de aplicar la acción | Nombre de acción | (...) Argumentos pasados a la acción |
| adquiridor | Se llama a un Getter | Nombre Getter | Valor del Getter |
| complemento | Se agrega un complemento | Complemento agregado | (...) Opciones pasadas al complemento |
| Registro de registro | Se registra un módulo | Espacio de nombres registrado | Definición del módulo | Tienda creada con la definición |
| no registrada | Un módulo no está registrado | Espacio de nombres no registrado | Tienda creada con la definición |
Al igual que Vuex, Dragonbinder le permite dividir su tienda en módulos y cada módulo puede contener su propia definición de almacenamiento, incluidos más módulos anidados.
const moduleA = {
state : { ... } ,
mutations : { ... } ,
actions : { ... } ,
getters : { ... }
}
const moduleB = {
state : { ... } ,
mutations : { ... } ,
actions : { ... } ,
getters : { ... }
modules : {
a : moduleA
}
}
const store = new Dragonbinder ( {
modules : {
b : moduleB
}
} ) ;
console . log ( store . state . b ) // -> `moduleB`'s state
console . log ( store . state [ 'b.a' ] ) // -> `moduleA`'s state Además, después de que se crea la tienda, puede registrar/no registrar módulos con los métodos registerModule y unregisterModule .
Considere que cuando no registra un módulo, solo sus módulos anidados iniciales no se registrarán con él.
const moduleA = {
state : { ... } ,
mutations : { ... } ,
actions : { ... } ,
getters : { ... }
}
const moduleB = {
state : { ... } ,
mutations : { ... } ,
actions : { ... } ,
getters : { ... } ,
modules : {
a : moduleA
}
}
const moduleC = {
state : { ... } ,
mutations : { ... } ,
actions : { ... } ,
getters : { ... }
}
const store = new Dragonbinder ( ) ;
store . registerModule ( 'b' , moduleB ) ;
store . registerModule ( 'b.c' , moduleC ) ;
console . log ( store . state . b ) // -> `moduleB`'s state
console . log ( store . state [ 'b.a' ] ) // -> `moduleA`'s state
console . log ( store . state [ 'b.c' ] ) // -> `moduleC`'s state
store . unregisterModule ( 'b' ) ;
console . log ( store . state . b ) // -> undefined
console . log ( store . state [ 'b.a' ] ) // -> undefined
console . log ( store . state [ 'b.c' ] ) // -> `moduleC`'s state Cada módulo se comportará como cualquier otra tienda, pero, a diferencia de Vuex, todos los módulos de Dragonbinder están afectados por el diseño. No hay opción para agregar mutaciones raíz, acciones o getters con un módulo. Entonces, cuando llame a una mutación, acción o getter de un módulo, debe suministrar su espacio de nombres completo.
El primer argumento para las mutaciones y los getters continuará siendo el estado local, y con las acciones el primer argumento será el contexto/tienda local.
Getters obtendrá el estado raíz y los getters de raíz como el tercer y cuarto argumentos.
Las acciones accederán al contexto raíz por la propiedad de rootStore del contexto local.
const moduleA = {
state : {
hello : 'world'
} ,
mutations : {
sayHello ( state , payload ) {
state . hello = payload ;
}
} ,
actions : {
change ( store , payload ) {
store . commit ( 'sayHello' , payload ) ;
store . rootStore . commit ( 'increment' ) ;
}
} ,
getters : {
hello ( state , getters , rootState , rootGetters ) {
return `You have said hello ${ rootState . count } times to ${ state . hello } ` ;
}
}
} ;
const store = new Dragonbinder ( {
state : {
count : 0
} ,
mutations : {
increment ( state ) {
state . count ++ ;
}
} ,
modules : {
a : moduleA
}
} ) ;
store . dispatch ( 'a.change' , 'John Doe' ) ;
console . log ( store . getters [ 'a.hello' ] ) ; // -> You have said hello 1 times to John Doe
console . log ( store . state . count ) // -> 1
console . log ( store . state . a . hello ) // -> John DoeDragonbinder viene con un sistema de complementos simple pero potente. Puede extender su funcionalidad central o cambiarla por completo haciendo uso de complementos.
let store = new Dragonbinder ( ) ;
store . use ( myPlugin , ... options ) ; Un complemento Dragonbinder es un módulo que exporta una sola función que se llamará con la instancia de la tienda como primer argumento y opcionalmente con las opciones aprobadas si las hay.
const Dragonbinder = require ( 'dragonbinder' ) ;
const myPlugin = ( store , ... options ) => {
Dragonbinder . myGlobalMethod = function ( ) {
// Awesome code here
} ;
Dragonbinder . fn . myPrototypeMethod = function ( ) {
// Awesome code here
} ;
store . myLocalMethod = function ( ) {
// Awesome code here
} ;
} ; Consulte los documentos en: https://masquerade-circus.github.io/dragonbinder/?api
Consulte la guía contribuyente en: https://masquerade-circus.github.io/dragonbinder/?content=contributing
yarn dev para ver y compilar la biblioteca en cada cambio.yarn build para construir la biblioteca.yarn test para ejecutar pruebas solo una vez.yarn dev:test para ejecutar las pruebas observando cambios en la biblioteca y las pruebas.yarn dev:test:nyc para ejecutar las pruebas de observación de cambios y obtenga la cobertura de prueba por fin.yarn docs para construir la documentación.yarn docs:watch para ver y reconstruir la documentación en cada cambio a la biblioteca o los archivos MD.yarn docs:serve para ver la documentación generada localmente. Autor: Masquerade Circus. Licencia Apache-2.0