Use mobx or redux or with repository pattern and persistent local storage realm or sqlite? - react-native

Mobx and Redux will normally not persist any data. They will maintain a temporary global state while the app is running.
I know there are redux-persist and mobx-persist packages within both communities. But unfortunately these persisting solutions do not seem good at all. They only stringify or serialize a global state tree and persist it using some sort of key-value storage. Right?
The problem:
When such an app is open again, the stringified store will be parsed and structured back to its original data structure (JSON, for instance) and then fully loaded into the RAM memory. Am I right?
If yes, this is a problem. It is not good to always have a full "database" aka "global state" loaded in-memory. It will probably never be faster to filter data within a long array in my global state... compared to querying a table on SQLite, right?
I have been looking for some repository-like solution for persisting global state for either redux or mobx. I am yarning for some solution for persisting and querying data on some well-known mobile database like SQLite or others.
Any answers will be very much appreciated.

Indeed you can use repository pattern.
On your repository, you may have a save method.
save(group: GroupLocalStorageModel): Promise<boolean> {
let created;
this._localStorage.write(() => {
created = this._localStorage.create<GroupLocalStorageModel>("Group", group);
});
return Promise.resolve(true);
}
This method will literally save your entity to some local storage you set. In the example above, we are saving a group object to a Group collection which are like tables. We are using realm which is no-sql.
Once you have your repository, if you are using either redux or mobx, you will probably call your save method on your action. Both redux and mobx work with actions, right?
export const GroupStoreModel = types
.model("GroupStore")
.props({
groups: types.optional(types.array(GroupModel), []),
})
.extend(withEnvironment)
.actions((self) => {
return ({
_addGroupToStore(group: GroupLocalStorageModel) {
self.groups.push(group)
},
_deleteAllFromStore() {
self.groups.clear()
},
_addGroupsToStoreBatch: (groups: GroupLocalStorageModel[]) => {
self.groups.concat(groups);
},
})
})
/* Async actions */
.actions((self) => {
let groupRepository = self.environment.groupRepository;
return ({
addGroup(group: GroupLocalStorageModel) {
groupRepository.save(group).then(result => self._addGroupToStore(group))
},
getAllGroupsPaginated(page: number) {
groupRepository.getAllPaginated(page).then(groups => self._addGroupsToStoreBatch(groups));
},
deleteAll() {
groupRepository.deleteAll();
self._deleteAllFromStore();
}
})
})
In this example, we are using mobx-state-tree. And this addGroup action will update firstly our database, and then update also the global state.
We still want to use our global state so our views will be re-rendered automatically according to either connect for redux or observable for mobx.
See more informations here on the repository:
https://github.com/Hadajung/poc-react-native-database-example

AFAIK, there are two options for using sqlite with redux persist.
redux-persist-sqlite-storage: By maintainer's own word
By default redux-persist uses AsyncStorage as storage engine in react-native. This is a drop-in replacemet of AsyncStorage.
The library is inspired by react-native-sqlite-storage.
Please, remember, to use this, you need to install an additional package installed react-native-sqlite-storage
redux-persist-sqlite: By maintainer's own word
A redux-persist storage adapter that writes to sqlite.
This is adapted from https://github.com/prsn/redux-persist-sqlite-storage, but uses Node.js sqlite3 rather than react-native.
Great for Electron apps that are backed by Redux.
UPDATE: react-native-mmkv : This is developed by WeChat. As it says in its about section
An extremely fast key/value storage library for React Native. ~30x faster than AsyncStorage!

I'm not really sure what you need but if I understood you correctly you need to persist large amounts of data, and also to load that same data, but only in batches.
I believe that this kind of problem can be solved with a repository pattern and SOLID design principles.
You will need:
store class (mobx store) that holds your business logic.
repository class which is responsible for retrieving and persisting data.
The store gets the repository injected into it via the constructor.
Then when you call the initialize method on your store, it talks to the repository and retrieves the initial data. Now, initial data can be only a subset of all the data that is persisted. And you can implement some kind of paging on the store and repository, to retrieve data in batches as needed. Later you can call other methods to load and save additional data as needed.
pseudo code:
class Repository(){
initialize()// load the first batch
load(next 10 models)
save(data)
}
class Store{
constructor(repository)
initialize(){
repository.initialize()
}
load(){
repository.load()
}
save(){
repository.save()
}
}
Now your application data shouldn't be one giant object, rather it should consist of multiple stores, where each store is responsible for a part of the data. For example, you would have one store and repository for handling todos and another pair that handles address book contacts etc.
Addendum:
The reason the repository is injected into the store is so you could easily swap it for some other implementation (the store doesn't care how the data is persisted and retrieved) and also, unit testing is very easy.
You could also have a root store that would hold all other stores, so in essence you have your complete state in one place. So if you call serialize on the root store, it serializes all stores and returns one big object.

I think the best solution would be bloc hydrated or cubit hydrated package from flutter_bloc.
https://pub.dev/packages/hydrated_bloc
In background it uses Hive DB, very performant DB, and only keys are stored in memmory so it should not add huge bloat to the app like SQLite.
If you could make all you APP logic in blocks/cubits, then extra DB calls would be irelevant.

Related

Most efficient way to filter an API response

I'm building a stock market overview app in Vue (+Vuex), getting market data from an API, then being updated every x seconds over websocket
Now i want to have a little section that shows "best performing markets"
I'm wondering what would be the most efficient way to handle this calculation.
(all in pseudocode)
1
(in vue component)
computed: {
getTopMarkets() {
filterTopMarkets(this.$store.state.markets)
}
}
2
(in vuex getter)
getters: {
topMarkets() {
return filterTopMarkets(state.markets)
}
}
#3
(other possibilities i am missing?)
is there a difference to the two approaches above (calculate in a computed property vs. calculate in a vuex getter)? is one faster than the other? better than the other? why?
thanks! :)
Both Vuex getters and computed component properties are JavaScript getters.
The long syntax of a computed is:
computed: {
yourComputed: {
get: function() { return expression }
}
}
equivalent of:
computed: {
yourComputed() { return expression }
}
and you can always define setters for computed:
computed: {
yourComputed: {
get: function() { return expression },
set: function(value) {
// dispatch an action or commit a mutation using value
}
}
}
This, combined with Vue's reactivity (or change detection mechanism) means that once they're run once, every time they're requested again Vue will serve the previously computed value - that's why they're called computed - (without actually re-running the code) until the moment any of the dynamic bits (references) change. When references change, the getter (whether it's a Vuex getter or a computed property) is rerun and all places where its referenced are notified (and those are re-run/re-rendered, in turn).
The only difference between the two cases is: Vuex getters are cached at store level, computed props are cached at component level.
In terms of both performance and change detection they're basically the same (internally they use the same mechanism).
Now, if you're only using this in one single component, the recommendation is not to use Vuex, as you'll have unnecessary additional boilerplate code around your data.
You're better off using a private store inside your component (either Vue.observable() or a Vue instance - before Vue.observable() was a thing, that was the way to create a basic Store without all the bells and whistles a Vuex store comes with).
Note: The mentioned alternatives allow you to expose the component's private store. If you don't need to expose it, don't bother: each component already has a private store: the data function (exposed to template). All you need to do is declare the reactive props upfront and from that point on the component will react to applied changes.
As already stated in the comment below your question, the choice here should not be based on code performance (as it's basically the same), but based on development and code management performance.
On how much your project will benefit from the order/structure Vuex comes with, in the long run:
how complex will your app get in time,
how many developers are/will be working on it and how well defined are the project's private conventions (if any)
how decoupled do you want/need data management and components to be)
how many iterations of this app are you expecting/foreseeing?
The more complex the project (codebase size, data structure complexity, app logic complexity, number of app iterations, number of developers), the more benefit you'll get from using Vuex, IMHO.

What is a difference between action,reducer and store in redux?

I am new to react/redux. I am trying to figure out how all the pieces in redux interact. The one thing giving me trouble is understanding the relation between actions and reducers,store.
It's pretty simple when you think about it:
Store - Is what holds all the data your application uses.
Reducer - is what manipulates that data when it recieves an action.
Action - is what tells reducer to manipulate the store data, it carries the name and (not required) some data.
Reducer is usually in a format of a switch statement, that switches between all possible Actions (Cases) and then manipulates the Store data based on action. When a reducer data changes within the redux, the properties in your components are changed and then the re-render ocurrs.
Store -> A Globalized state
Action -> What you wanna do, eg: event click
Reducer -> Describes how your action transfers state into the next state.
It checks which action took place and based on the action it updates the store.
Dispatch -> Way how we execute the action. eg: Dispatch the action to the reducer. Then reducer will check what to do and the store gets updated.
Store
An Object that holds the applications state data
Reducer
A function that returns some state data. Is triggered by an action type
Action
An object that tells the reducer how to change the state. It must contain a type property. It can optionally contain a payload property
The actions, reducers and stores are the three building blocks of redux.
Actions: Actions are the only source of information for the store. Actions have a type field that tells what kind of action to perform and all other fields contain information or data. And there is one other term called Action Creators, these are the function that creates actions. So actions are the information (Objects) and action creator are functions that return these actions.
Reducers: As we already know, actions only tell what to do, but they don’t tell how to do, so reducers are the pure functions that take the current state and action and return the new state and tell the store how to do.
Store: The store is the object which holds the state of the application.
I found this link to be particularly helpful - https://www.geeksforgeeks.org/introduction-to-redux-action-reducers-and-store/
Imagine a situation where you want your class based components to share data among each other. They may even bring changes to the data. One may provide data to others in the form of props. But it very difficult to keep track of the name of the props and the structure of data.
The Store actually simplifies this stuff. You set up your application architecture in such a way that the components will get their data from the supply what is known as the Store. Actually, the mechanism is so smart the component will re-render itself when the data changes since the components are all ears.
And Actions are nothing but the carriers of data from your application to the store.
And it is very difficult to articulate the concept of reducers. You may imagine a real store where one puts different stuff for future use. The store is of no use when the stuff is put haphazardly. One may spend hours inside but may not find anything. The Reducers in simple terms manage the way data is kept in store provided by the actions.
according to redux documents:
store: The whole global state of your app is stored in an object called store.
dispatcher: To change something in the state, you need to dispatch an action. (and that is what dispatcher does)
action: An action is a plain JavaScript object that describes the kind of change to make (as dictated by action.type) to the store and the relevant payload required for that change.
reducer: to tie state and actions together, we write a function
called a reducer. it’s just a (pure) function that takes state and action as arguments and returns the next state of the app.
for a deeper understanding look at the diagram in this link.
Actions: Actions are a plain JavaScript object that contains information. Actions are the only source of information for the store. Actions have a type field that tells what kind of action to perform and all other fields contain information or data.
Example :
function addTask(task) {
return {
type: 'ADD_TODO',
task: task
}
}
Reducers: As we already know, actions only tell what to do, but they don’t tell how to do, so reducers are the pure functions that take the current state and action and return the new state and tell the store how to do.
Example:
function task(tasks = [], action) {
if (action.type === 'ADD_TODO') {
return [...tasks, action.task];
} else if (action.type === 'REMOVE_TODO') {
return tasks.filter(task => task !== action.task);
}
return tasks;
}
Store: The store is the object which holds the state of the application.
ref: https://www.geeksforgeeks.org/introduction-to-redux-action-reducers-and-store/

Performance issues with large datasets

Is there any way of filtering the events in a projection associated with a read model by the aggregateId?
In the tests carried out we always receive all registered events. Is it possible to apply filters in a previous stage?
We have 100,000 aggregateId and each id has associated 15,000 events. Unable to filter by aggregateId, our projections have to iterate over all events.
So you have 100.000 aggregates with 15.000 events each.
You can use ReadModel or ViewModel:
Read Model:
Read model can be seen as a read database for your app. So if you want to store some data about each aggregate, you should insert/update row or entry in some table for each aggregate, see Hacker News example read model code.
It is important to understand that resolve read models are built on demand - on the first query. If you have a lot of events, it may take some time.
Another thing to consider - a newly created resolve app is configured to use in-memory database for read models, so on each app start you will have it rebuilt.
If you have a lot of events, and don't want to wait to wait for read models to build each time you start the app, you have to configure a real database storage for your read models.
Configiuring adapters is not well documented, we'll fix this. Here is what you need to write in the relevant config file for mongoDB:
readModelAdapters: [
{
name: 'default',
module: 'resolve-readmodel-mongo',
options: {
url: 'mongodb://127.0.0.1:27017/MyDatabaseName',
}
}
]
Since you have a database engine, you can use it for an event store too:
storageAdapter: {
module: 'resolve-storage-mongo',
options: {
url: 'mongodb://127.0.0.1:27017/MyDatabaseName',
collectionName: 'Events'
}
}
ViewModel
ViewModel is built on the fly during the query. It does not require a storage, but it reads all events for the given aggregateId.
reSolve view models are using snapshots. So if you have 15.000 events for a give aggregate, then on the first request all those events will be applied to calculate a vies state for the first time. After this, this state will be saved, and all subsequent requests will read a snapshot and all later events. By default snapshot is done per 100 events. So on the second query reSolve would read a snapshot for this view model, and apply not more than 100 events to it.
Again, keep in mind, that if you want snapshot storage to be persistent, you should configure a snapshot adapter:
snapshotAdapter: {
module: 'resolve-snapshot-lite',
options: {
pathToFile: 'path/to/file',
bucketSize: 100
}
}
ViewModel has one more benefit - if you use resolve-redux middleware on the client, it will be kept up-to-date there, reactively applying events that app is receiving via websockets.

Use redux if all the data is in ajax requests or database

I am new to react, specifically in native and I am in the dilemma if I use redux to maintain the data store if most of these will be in local database. At the moment I have thought about having a "categories" with a single case that would be of the SET_DATA type and every time I need to filter the data I call asynchronous actions methods that load the necessary data and perform the dispatch for the reducer. An example of my code is like this (where ALL_CATEGORY and BY_NAME_CATEGORY are queries):
categoryAction:
import {SET_CATEGORIES} from "../constants/actionTypes";
import {ALL_CATEGORY, BY_NAME_CATEGORY} from "../constants/db/load";
import {dbTransaction} from '../database/dbbase';
export const setCategories = (data) => {
return {
type: SET_CATEGORIES,
payload: data
};
};
export const allCaregories = () => {
return (dispatch) => {
dbTransaction(ALL_CATEGORY)
.then((data)=> {
dispatch(setCategories(data));
}).catch((error)=> console.log('ALL_CATEGORY ERROR'));
};
};
export const byNameCaregories = () => {
return (dispatch) => {
dbTransaction(BY_NAME_CATEGORY)
.then((data)=> {
dispatch(setCategories(data));
}).catch((error)=> console.log('BY_NAME_CATEGORY_CATEGORY ERROR'));
};
};
And de categoryReducer is:
import {SET_CATEGORIES} from "../constants/actionTypes";
const initialState = [];
const categoryReducer = (state = initialState, action) => {
switch (action.type){
case SET_CATEGORIES:{
return action.payload;
}
default:
return state;
}
};
export default categoryReducer;
This works, but my query is why not choose to create methods to directly call the local database without using redux? Is there any advantage using redux or is it just to separate the application in layers?
Same case if the data were 100% in a web service, what would be the advantage of using redux if the data will always be obtained from an external source to redux
why not choose to create methods to directly call the local database
without using redux?
You can definitely choose to not use redux for your application; React/React Native or any other framework has no dependency on Redux. Redux isn't anything special, it's actually only a couple dozen lines of code to organize the way your application deals with state. In my honest but biased opinion, I would use Redux if I think an application might need to scale beyond 1,000+ (very arbitrary number) users or have more than 1 developer.
Is there any advantage using redux or is it just to separate the application in layers?
There is no advantage to using Redux beyond maintainability and standardization.
Your application might seem simple now only having to query a local database, you can definitely use custom methods to update the store. But, what happens when you need to make api requests too? Or when you need to add undo functionality? Will your code be comprehensible to new teammates? Ultimately, by using redux your chances of incurring technical debt are reduced.
Same case if the data were 100% in a web service, what would be the
advantage of using redux if the data will always be obtained from an
external source to redux
It will be no different than querying a local database. Redux doesn't care where you get data from it only handles where the Store is, when it should change, and how it should change.
Redux is handy if/when you decide that your app would benefit from having a global state store that's accessible from any component that needs it. I tend to use Redux in the following cases:
Two or more components need to access some common state and making that happen would be unreasonably difficult/messy without Redux (maybe the most important criterion).
You have components that depend upon the payload of an expensive REST call/db query/etc and it makes sense to temporarily persist that payload for future uses rather than perform the expensive call again, particularly when the above point is also true and/or your app has use cases that change that data locally.
You have payload data that requires elaborate formatting/filtering/parsing after being fetched in order to be properly used by your components (hey, APIs don't always give us what we need exactly how we need it in real life).
In your particular case, it may be that the db queries you need to make aren't particularly expensive, and you can let the db handle the filtering for you. If this is your main concern, Redux might be a bit more overhead than you need.

Flux without data caching?

Almost all examples of flux involve data cache on the client side however I don't think I would be able to do this for a lot of my application.
In the system I am thinking about using React/Flux, a single user can have 100's of thousands of the main piece of data we store (and 1 record probably has at least 75 data properties). Caching this much data on the client side seems like a bad idea and probably makes things more complex.
If I were not using Flux, I would just have a ORM like system that can talk to a REST API in which case a request like userRepository.getById(123) would always hit the API regardless if I requested that data in the last page. My idea is to just have the store have these methods.
Does Flux consider it bad that if I were to make request for data, that it always hit the API and never pulls data from a local cache instance? Can I use Flux in a way were a majority of the data retrieval requests are always going to hit an API?
The closest you can sanely get to no caching is to reset any store state to null or [] when an action requesting new data comes in. If you do this you must emit a change event, or else you invite race conditions.
As an alternative to flux, you can simply use promises and a simple mixin with an api to modify state. For example, with bluebird:
var promiseStateMixin = {
thenSetState: function(updates, initialUpdates){
// promisify setState
var setState = this.setState.bind(this);
var setStateP = function(changes){
return new Promise(function(resolve){
setState(changes, resolve);
});
};
// if we have initial updates, apply them and ensure the state change happens
return Promise.resolve(initialUpdates ? setStateP(initialUpdates) : null)
// wait for our main updates to resolve
.then(Promise.params(updates))
// apply our unwrapped updates
.then(function(updates){
return setStateP(updates);
}).bind(this);
}
};
And in your components:
handleRefreshClick: function(){
this.thenSetState(
// users is Promise<User[]>
{users: Api.Users.getAll(), loading: false},
// we can't do our own setState due to unlikely race conditions
// instead we supply our own here, but don't worry, the
// getAll request is already running
// this argument is optional
{users: [], loading: true}
).catch(function(error){
// the rejection reason for our getUsers promise
// `this` is our component instance here
error.users
});
}
Of course this doesn't prevent you from using flux when/where it makes sense in your application. For example, react-router is used in many many react projects, and it uses flux internally. React and related libraries/patters are designed to only help where desired, and never control how you write each component.
I think the biggest advantage of using Flux in this situation is that the rest of your app doesn't have to care that data is never cached, or that you're using a specific ORM system. As far as your components are concerned, data lives in stores, and data can be changed via actions. Your actions or stores can choose to always go to the API for data or cache some parts locally, but you still win by encapsulating this magic.