Smaller, faster, better event-driven state management architecture that supports asynchronicity and state persistence out of the box with no extra code.
From 5.0.10, the changelogs on the project will be kept in CHANGELOG, which follows keepachangelog.
demo-typings_J13zCqab.mp4
git clone git@github.com:aprilmintacpineda/fluxible-js.git
yarn
yarn test
yarn add fluxible-js
import { createStore } from 'fluxible-js';
const initialStore = {
user: null,
someOtherState: 'value',
anotherState: {
value: 'value'
}
};
const store = createStore({
initialStore,
persist: {
stringify: true,
syncStorage: {
setItem: (key, value) =>
window.localStorage.setItem(key, value as string),
getItem: key => window.localStorage.getItem(key)
},
restore: savedStore => ({
user: savedStore.user
})
}
});
import { createStore } from 'fluxible-js';
const initialStore = {
user: null,
someOtherState: 'value',
anotherState: {
value: 'value'
}
};
function initCallback () {
console.log('initialization complete');
}
const myStore = createStore({ initialStore }, initCallback);
createStore
function returns an instance of a store
that has variety of methods in it. You can access the store's current value by via myStore.store
. The 2nd parameter which is the initCallback
is optional function that gets called after the store has been initialized, this is especially useful when using async storage.
Persisting states allows you to save your application's state to a storage on the local device and then reuse those states the next time your application starts.
You need to tell fluxible-js
which storage to use, a storage API must have a getItem
and setItem
methods in them. An example of this would be window.localStorage or React-Async-Storage
You also need to tell fluxible-js
which states to persist, you can do this via the restore
callback function.
You need to tell fluxible-js
if the states has to be stringified (using JSON.stringify
) before being saved to the storage by specifying stringify
parameter.
setItem
and getItem
should be async or should return a promise, pretty much like with React-Native-Async-Storage. See example use-case with react-fluxible.
import { createStore } from 'fluxible-js';
const initialStore = {
token: null,
isLoggedIn: false,
initComplete: false
};
const store = createStore(
{
initialStore,
persist: {
stringify: true,
asyncStorage: {
setItem: (key, value) => someAsyncStorage.setItem(key, value as string), // value will be a string because `stringify` is set to `true`
getItem: key => someAsyncStorage.getItem(key) // has to be a string because `stringify` is set to true
}
restore: (savedStore) => {
return {
token: savedStore.token
};
}
}
},
() => {
store.updateStore({ initComplete: true });
}
);
getItem
and setItem
should be sync, pretty much like with window.localStorage. See example use-case with react-fluxible.
import { createStore } from 'fluxible-js';
const initialStore = {
token: null,
isLoggedIn: false
};
const store = createStore({
initialStore,
persist: {
stringify: true,
syncStorage: {
setItem: (key, value) =>
window.localStorage.setItem(key, value as string), // value will be a string because `stringify` is set to `true`
getItem: key => window.localStorage.getItem(key) // has to be a string because `stringify` is set to true
},
restore: (savedStore) => {
return {
token: savedStore.token
};
}
}
});
If you don't care that much about typings, you can also just do:
syncStorage: window.localStorage as SyncStorage<typeof initialStore>,
or
syncStorage: ReactNativeAsyncStorage as AsyncStorage<typeof initialStore>,
You can update the store by doing:
import { createStore } from 'fluxible-js';
const initialStore = {
token: null,
isLoggedIn: false
};
const store = createStore({
initialStore,
persist: {
stringify: true,
syncStorage: {
setItem: (key, value) =>
window.localStorage.setItem(key, value as string),
getItem: key => window.localStorage.getItem(key)
},
restore: (savedStore) => {
return {
token: savedStore.token
};
}
}
});
// somewhere in your code
store.updateStore({
token: userToken,
isLoggedIn: true
});
Observers are callback functions that listen to certain changes in your store. Observers will be called AFTER the store has been updated and they will receive the updated store. You can add an observer by doing:
import { createStore } from ".";
const store = createStore({
initialStore: {
token: null
}
});
store.addObserver(
(store) => {
console.log(store.token);
// do something
},
// states that you want to watch changes for
['token']
);
Observers will only be called when the state they are watching changes, in this case, the observer is only watching token
, so this observer will only be called when you do store.updateStore({ token })
. This prevents unnecessary calls to all observers when other states changes.
You can add, emit, and remove events in your store. You can take advantage of events to do various things in your applications such as updating the store.
import { createStore } from ".";
const store = createStore({
initialStore: {
token: null
}
});
/**
* Event callbacks receive the:
* payload = passed on emitEvent
* store = the latest value of thes store
* event = the event that was emited, this is useful when using `addEvents`
*/
const unsubscribeCallback = store.addEvent('test-event', (payload, store, event) => {
console.log(payload, store, event);
// do something
});
// when you want to remove the event listener from the event
unsubscribeCallback();
There is also addEvents
in case you want an event listener to listen to multiple events.
const unsubscribeCallback = store.addEvents(
['event1', 'event2', 'event3'],
(payload, store, event) => {
console.log(payload, store, event);
// do something
}
);
// when you want to remove the event listener from the event
unsubscribeCallback();
store.emitEvent(
'event1',
// optional: any value you want to pass to all the event listeners
{ value: 1 }
);
store.emitEvents(
['anEvent', 'anotherEvent'],
// optional: any value you want to pass to all the event listeners
{ value: 1 }
);
store.removeEvent('event1');
store.removeEvents(['anEvent', 'anotherEvent']);
The only changes that occured in v6 are the following:
- Used TypeScript for better coding experience.
- Changed architecture to be more self-contained.
- No more
-1
returns.
Your code should still work with minimal changes. Here's how you can migrate real quick.
Create a file called globalStore.ts
, and add the following code:
import { createStore } from 'fluxible-js';
const initialStore = {
// ... your store values here
};
export default createStore({
initialStore,
// ... other options
});
Now, change all occurences of import { updateStore } from 'fluxible-js';
and other similar imports to import { updateStore } from 'globalStore';
.