Performing a state persistance in Aurelia Store - persistence

We have a basic app state that needs to be persisted upon the browser refresh. similar to vuex-state-persistance plugin. Here is the basic state code that needs to be persisted.
export const initialState = {
user: {
uuid: 'wedRfertYjsnjnakUiisdj878HBhsns',
name: 'Kiran Maniya',
scope: 'user'
}
};
Is there anything that can be used directly as a plugin or I need to write a custom plugin that persists the state in localStorage asynchronously? Also, how do we modularise the state when we have a complex and large state to manage?

Aurelia Store provides a built-in mechanism to persist state in localStorage.
So, if your initialState goes initialized in main.ts or main.js something like this:
aurelia.use.plugin('aurelia-store', { initialState: initialState });
Then in app.ts or .js you should register the localstorage middleware and perform a rehydration.
So, in app constructor, you could write:
import { localStorageMiddleware, rehydrateFromLocalStorage, Store } from 'aurelia-store';
import { initialState, State } from 'state';
...
constructor(
private store: Store<State>,
) {
store.registerMiddleware(localStorageMiddleware, MiddlewarePlacement.After, { key: ¨someKey¨ });
store.registerAction('Rehydrate', rehydrateFromLocalStorage);
}
Regarding modularization, maybe you should combine store and the EventAggregator to implement more complex scenarios.
Good luck

Related

Understanding Cubit/Bloc state management

I'm new to flutter and I have experience in web application using state managements like Redux or Vuex where the initial state of a module might be something like:
{
value1: 0,
value2: 10,
aBool: false,
aString: 'Hello'
}
Then based on Reducers or Mutations we can update a single or multiple properties of the state.
Now, learning Flutter I decided to use Bloc/Cubit and online I cannot find the right answer to my problem, even because the majority of the example are always based on the crappy counter app and never on a more realistic scenario.
All I can see is something based on 4 states in Bloc: initial, loading, success and error.
This is fine when fetching data from an API, but what if my state has also more properties?
how to update those properties?
Actually I created my test Cubit to fetch something from my API, it works. Now I wish to add more properties on the state and update it based on actions, how can I do that?
Example state:
#freezed
abstract class TestState with _$TestState {
const factory TestState.initial() = _Initial;
const factory TestState.loading() = _Loading;
const factory TestState.success(UserData user) = _Success;
const factory TestState.error(String message) = _Error;
}
Example Cubit:
class TestCubit extends Cubit<TestCubit> {
TestCubit(this._testClient)
: super(TestState.initial());
final TestClient _testClient;
String greet = 'Hi';
Future<void> testFetchData() async {
...
emit(TestState.success(testData));
...
}
}
I can successfully handle the varioud initial, loading, etc... states.
I can correctly watch at the greet property: context.read<TestCubit>().greet
How should I now update that value with 'hello!'?
// TestCubit
updateGreet(String text) {
emit(I don't know);
}
I omitted all my various tries to update that value.
Thanks

Denormalization practices in reactive application

I am creating a reactive application with Meteor (with MongoDB as a backend).
I initially created a non-reactive-aware collection and denormalizers, eg.:
class DocCollection extends Mongo.Collection {
insert(doc, callback) {
const docId = super.insert(doc, callback);
doc = docMongo.findOne(docId); // for illustration, A
console.log(doc);
return docId;
}
}
docMongo = new DocCollection();
Now, I'd like to wrap it into MongoObservable, which will facilitate listening to the changes to the collection:
export const Doc = new MongoObservable.Collection(docMongo);
Then, I define a Method:
Meteor.methods({
add_me() {
Doc.insert(myDoc);
}
});
in server/main.js and call it in app.component.ts's constructor:
#Component(...)
export class AppComponent {
constructor() {
Meteor.call('add_me');
}
}
I get undefined printed to console (unless I sleep a little before findOne), so I suppose when I was looking for the doc after insertion in my Mongo.Collection, the document wasn't yet ready to be searched for.
Why does it happen, even though I overwrote the non-reactive class and only then wrapped it in MongoObservable?
How do I typically do denormalization with a reactive collection? Should I pass observables to my denormalizers and there create new ones, or is it possible to nicely wrap the non-reactive code afterwards (like I tried and failed above)? Note that I don't want to directly pass doc inside, as in more complex scenarios it will cause other inserts/updates elsewhere for which I'd also want to wait.
How do people typically test these things? If I run a test, the code above may succeed locally, as db insertion time is small, but fail when the delay is higher.

How do I initialize a long-lived class in a Flutter app?

I have an Api class that accepts an (optional) authentication token that it uses for making authenticated requests e.g. Api(token: 'a9sa2ksas12').getUserDetails().
If the token is not passed, it has to perform the relatively expensive operation of reading it from sharedPreferences.
class Api {
static const BASEURL = "https://api.google.com/";
final String token;
Api({ this.token });
Future<http.response> getUserDetails() async {
return http.get('$BASEURL/user/', headers: { 'Authorization': token });
}
}
How can I setup my app so that the token is read only once from sharedPreferences and used throughout the app for all future Api() requests?
Some ideas I've considered and think that may work:
Have token be a global variable
Make the API class a singleton, and pass it around between "screens"
Well in general there's nothing bad in making you Repositories a singletons. But on the other hand, I don't like the concept of passing the API classs between the screens.
When widgets use your data source directly without any middleman, like Bloc or Provider, they tend to be polluted with a lot of presentation logic. I personally prefer to separate those concerns and let widgets do what they are made for: rendering the UI. This makes them smaller and easier to test.
What's more the API class should be responsible only for the network calls. It shouldn't be responsible for managing the token. I'd inject to the API class something like:
class TokenProvider
{
Future<String> getToken();
}
The responsibility of this class would be, you guessed it, to provide a token. It can return cached value or get it from the SharedPreferences. Thanks to this the API doesn't have to care where the token comes and how to handle it. It will do just one thing: api calls.
I ended up using the "Locator" pattern, via get_it.
The code was pretty simple.
Step 1: Setup a top-level locator.dart in lib/
// ./lib/locator.dart
import 'package:my_app/services/api.dart';
import 'package:get_it/get_it.dart';
GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton(() => Api());
}
Step 2: Use api anywhere in the app by just importing the locator:
// ./lib/widgets/some_screen.dart
class _SomeScreenState extends State<SomeScreen> {
Api api = locator<Api>();
#override
void initState() {
api.getUserDetails().then((response) => {
// do anything you like with the response
});
super.initState();
}
The beauty of this approach is that Api is only ever initialized ONCE in the lifetime of the app, so I simply assign a token to it on initState without worrying about the widget getting disposed/rebuilt and repeated fetches to SharedPreferences.

Twitter-like app with Angular2 ngrx. Structuring AppState

I've been looking at the ngrx and redux pattern lately and am thinking how would I rewrite my existing Angular2 app into using ngrx/store.
What I have is an app where users can view and (if signed in) can like and publish citations.
A typical citation object looks like this:
{
text: "Success is the ability to go from one failure to another with no loss of enthusiasm.",
publisher: user12345,
rank: 14,
//some more data
}
Application strucure looks like the following:
Home page - either with registration/login form or with random citation (if signed in).
Profile page with tabs
Tab with all citations published by the user and a form to publish a new one.
Profile info
Citations feed page
Page to view other user's profile with similar structure as above. (when user clicks on the citation's publisher).
So, I'm quite frustrated of how would the AppState tree look like.
AppState {
UserState {
UserCitationsState,
UserInfoState,
AuthState
},
RouterState,
UserPageState //State representing the other user's page viewed
//etc
}
The main question is - what should I store in each state since all the data is fetched per-request from the backend REST api. Would it be just boolean values like e.g.:
UserPageState {
loading: false,
loaded: true
}
or should it also store all the information and just replace it every time a new user page is requested? As every time user navigates to some other's user page all the data is fetched from the backend.
That's the point of fundamental confusion for me - how to handle these kind of apps with redux.
EDIT
At the moment I limited myself with 5 states (5 reducers) to represent the overall app:
AuthState
UserState
UserListState
CitationState
CitationListState
However, in the overall app state I'm duplicating many of them. I guess it's fine. Or would there be an even better way?
export interface AppState
{
localUser: AuthState
//homePage
homeCitation: CitationState
//profilePage
profileInfo: UserState
profileCitations: CitationListState
favouriteCitations: CitationListState
subscribers: UserListState
//userPage (when local user navigates to citation publisher's profile)
userInfo: UserState
userCitations: CitationListState
userSubscribers: UserListState
//feedPage
feed: CitationListState
//.....
}
My initial thoughts on this to think of the application state much like you would a database.
I would structure using the following reducers:
AppState: {
CitationState
UserProfileState,
UserInfo,
RouterState
}
interface CitationState {
citations: Citation[]
}
interface UserProfileState {
userProfiles: UserProfile[]
}
interface UserInfo {
userInfo: UserInfo
}
interface Citation {
id: number;
publisherId (userId): number;
rank: number;
text: string;
}
interface UserProfile {
userId: number;
citationIds: number[]
}
interface UserInfo {
userId: number;
authToken: string;
}
Each smart component would then compose the data as necessary to render the view. For example, you can determine if the user profile is your own, by checking to see if the routed user profile matches the one in the UserInfo reducer.
Don't be concerned about creating loading/loading in state, this is something you could derive from the state of your store. Since all the data is observable, when you query from it, you are given the latest snapshot of available data.
Instead of binding to a loading property of the store when loading a user's citations, instead build a query for that data.
For example:
let userCitation$ = state.select(appState => appState.citations)
.map(citations => {
let userCitation = citations.find(c => c.id === userId);
return {
loaded: !!userCitation,
userCitation: userCitation
};
});

Angular2 multiple components using one REST call

I am part of a Angular2 application (we use beta3) and the issue is the following:
Usually we have a component that uses some service that uses some rest call and the component displays the data. Great.
However we do have a page with more then 6 components all of them using the same REST call...(the backend returns data for ALL of them) and it doesn't make sense to call 6 times the REST for each component, also it will be weird if we do some client side caching.
Is there something available out of the box ? Or a Pattern to handle such case?
Thanks.
Just do it in a shared service. If you add it only in bootstrap(..., [OtherProviders, HTTP_PROVIDERS, MyService]) each component will get injected the same instance. Store the data in the service and every component can access it
export class MyComponent {
constructor(private dataService:MyService) {
dataService.getData().subscribe(data => { this.data = data; });
}
}
export class MyService {
getData() {
if(!this.data) {
return http.get(...).map(...).subscribe(data => { this.data = data;});
}
return this.data;
}
}
The #Günter's answer really makes sense!
I don't know your code is organized but observable can also be subscribed several times. To do that you need to make them "hot" using the share operator:
export class MyService {
dataObservable:Observable;
initDataObservable() {
this.dataObservable = http.get(...).map(...).share();
}
}
Without using the share operator, corresponding request will executed several times (one per subscribe).
You can notice that the request will be executed once one subscribe method is called on the observable.