I'm developing a web app backed with firebase realtime database.
The app's frontend is quite complex and there are several methods that write data to the db. I have several utils that look like this:
var utils = {
setSomething: function(id, item) {
var myRef = firebase.database().ref('my/path');
myRef.set(item).then(something);
}
}
The question here is: is it okay to create a new Ref inside the method (and thereby, creating a new ref with each call) or should I "cache" the ref somewhere else (just like we cache jquery objects).
I could do something like this first:
var cachedRefs = {
myRef: firebase.database().ref('my/path'),
yourRef: firebase.database().ref('your/path'),
herRef: firebase.database().ref('her/path')
}
And then the former method could be rewritten as:
var utils = {
setSomething: function(id, item) {
cachedRefs.myRef.set(item).then(something);
}
}
Is there any performance gain besides having less code repetition?
firebaser here
References just contain the location in the database. they are cheap.
Adding the first listener to a reference requires that we start synchronizing the data, so that is as expensive as the data you listen to. Adding extra listeners is then relatively cheap, since we de-duplicate the data synchronization across listeners.
Related
I have a set of related items like so:
book {
id
...
related_entity {
id
...
}
}
which apollo caches as two separate cache objects, where the related_entity field on book is a ref to an EntityNode object. This is fine, the related entity data is also used elsewhere outside of the context of a book so having it separate works, and everything seems well and good and updates as expected...except in the case where the related entity does not exist on the initial fetch (and thus the ref on the book object is null) and I create one later on.
I've tried adding an update function to the useMutation hook that creates the aforementioned related_entity per their documentation: https://www.apollographql.com/docs/react/caching/cache-interaction/#example-adding-an-item-to-a-list like this:
const [mutateEntity, _i] = useMutation(CREATE_OR_UPDATE_ENTITY,{
update(cache, {data}) {
cache.modify({
id: `BookNode:${bookId}`,
fields: {
relatedEntity(_i) {
const newEntityRef = cache.writeFragment({
fragment: gql`
fragment NewEntity on EntityNode {
id
...someOtherAttr
}`,
data: data.entityData
});
return newEntityRef;
}
}
})
}
});
but no matter what I seem to try, newEntityRef is always undefined, even though the new EntityNode is definitely in the cache and can be read just fine using the exact same fragment. I could give up and just force a refetch of the Book object, but the data is already right there.
Am I doing something wrong/is there a better way?
Barring that is there another way to get a ref for a cached object given you have its identifier?
It looks like this is actually an issue with apollo-cache-persist - I removed it and the code above functions as expected per the docs. It also looks like I could instead update to the new version under a different package name apollo3-cache-persist, but I ended up not needing cache persistence anyway.
I want to create a really basic CRUD (sort-of) example app, to see how things work.
I want to store items (items of a shopping-list) in an array, using functions defined in my listService.js such as addItem(item), getAllItems() and so on.
My problems come when using the same module (listService.js) in different files, because it creates the array, in which it stores the data, multiple times, and I want it to be like a static "global" (but not a global variable) array.
listService.js looks like this:
const items = [];
function addItem (item) {
items.push(item);
}
function getItems () {
return items;
}
module.exports = {addItem, getItems};
and I want to use it in mainWindowScript.js and addWindowScript.js, in addWindowScript.js to add the elements I want to add to the array, and in mainWindowScript.js to get the elements and put them in a table. (I will implement later on Observer pattern to deal with adding in table when needed)
addWindowScript.js looks something like this:
const electron = require('electron');
const {ipcRenderer} = electron;
const service = require('../../service/listService.js');
const form = document.querySelector('form');
form.addEventListener('submit', submitForm);
function submitForm(e) {
e.preventDefault();
const item = document.querySelector("#item").value;
service.addItem(item);
console.log(service.getItems());
// This prints well all the items I add
// ...
}
and mainWindowScript.js like this:
const electron = require('electron');
const service = require('../../service/listService.js');
const buttonShowAll = document.querySelector("#showAllBtn")
buttonShowAll.addEventListener("click", () => {
console.log(service.getItems());
// This just shows an empty array, after I add the items in the add window
});
In Java or C#, or C++ or whatever I would just create a Class for each of those and in main I'd create an instance of the Service and pass a reference of it to the windows. How can I do something similar here ?
When I first wrote the example (from a youtube video) I handled this by
sending messages through the ipcRenderer to the main module, and then sending it forward to the other window, but I don't want to deal with this every time there's a signal from one window to another.
ipcRenderer.send('item:add', item);
and in main
ipcMain.on('item:add', (event, item) => {
mainWindow.webContents.send('item:add', item);
})
So, to sum up, I want to do something like : require the module, use the function wherever the place and have only one instance of the object.
require the module, use the function wherever the place and have only one instance of the object.
TL:DR - no, that isn't possible.
Long version: Nature of Electron is multi process, code you runs in main process (node.js side) and renderer (chromium browser) is runnning in different process. So even you require same module file, object created memory in each process is different. There is no way to share object between process except synchrnonize objects via ipc communication. There are couple of handful synchronization logic modules out there, or you could write your module do those job like
module.js
if (//main process)
// setup object
//listen changes from renderer, update object, broadcast to renderer again
else (//rendere process)
//send changes to main
//listen changes from main
but either cases you can't get away from ipc.
I am doing a POC for isomorphic JavaScript application to render HTML from the server side. The POC is working with simple HTML, but I want to make an API call and get the JSON response and send to the render function. I tried various ways but it is not working.
What am I missing? I am very new to React.js.
loadCategoriesFromServer: function() {
var self = this;
// get walking directions from central park to the empire state building
var http = require("http");
url = "api url here";
var request = http.get(url, function (response) {
// data is streamed in chunks from the server
// so we have to handle the "data" event
var buffer = "",
data,
route;
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
data = JSON.parse(buffer);
//console.log(data.d);
//console.log(data.d.Items);
self.setState({
categories: data.d.Items
});
});
});
}, // load from server end
getInitialState: function() {
return { categories: [] };
},
componentWillMount: function() {
console.log("calling load categories")
this.loadCategoriesFromServer();
},
render: function () {
//console.log("data");
//console.log(this.state.categories);
var postNodes = this.state.categories.map(function (cat) {
console.log(cat);
});
return (
<div id="table-area">
//i want to paint the data here..
</div>
)
}
});
Fetching inside of component using componentWillMount is not a right place, in case when you need to render server side. You need to somehow move it out form component, and pass actual data as props after it is fetched - for example as #JakeSendar suggested in his answer.
I have some experience doing isomorphic app with React, and the main problem I faced is how to wait until all data would be loaded before first render
As #FakeRainBrigand already mentioned in comments, there is not only one way to do this, and it depends from your requirements.
There is few ways to do build an isomorphic app, the some interesting from my perspective is: https://github.com/webpack/react-starter and http://fluxible.io/
But, the most elegant way to do this, as I figured out for myself - is to organise asynchronous rendering for react components, in particular using RxJS.
In general my application is structured as following:
views - React components without any logic (just a view)
models - Observables with current state (initial data is loaded using superagent, then combined with other models and/or actions results).
In simple case it is something like:
Rx.Observable.defer(fetchData).concat(updatesSubject).shareReplay()
actions(or intents) - Observers used to collects user input, do something, and dispatch action results to subscribers models and/or other actions. In simple case something like:
updatesSubject = new Rx.Subject();
action = new Rx.Subject();
action.switchMap(asyncRequest).subscribe(updatesSubject)
components - Observables(stream of virtual DOM elements) combined from models, other components and actions (I have a note about this, explaining how and why to create Observable React elements with RxJS), also now I am planning to add partial components (tuple from: react component, observables, observers, and properties. partially filled with using DI)
router - component responsible to handling location changes,
in general main feature is to map location changes to stream of virtual DOM elements and meta information. But in details, it is bit more complicated in my case(url generation, active url highlighting, handling scrolls when navigating, also it has possibility of nested routes and multiple views)
All this is assembled together using DI container, in my case similar to angular2 DI container, but a lot simplified for my specific needs.
Components, models and actions are created using DI.
On server side application is like this:
var rootInjector = new Injector();
// setup server specific providers
rootInjector.provide(..., ...)
app.get('/*', function(req,res){
var injector = rootInjector.createChild();
// setup request specific providers
injector.provide(..., ...);
injector.get(Router)
.first()
.subscribe(function(routingResult){
res.render('app', {
title: routingResult.title,
content: React.renderToString(routingResult.content)
});
});
}
and similar on client side:
var rootInjector = new Injector();
// setup server specific providers
// actually this is omitted in my case because default providers are client side
rootInjector.provide(..., ...)
contentElement = document.getElementById('#content');
rootInjector.get(Router)
.subscribe(function(routingResult){
document.title = routingResult.title;
React.render(routingResult.content, contentElement)
});
In comparison to flux, it is more declarative and more powerful way to organise app. And in case of isomorphic app - for me, it looks much better that various hacks with flux. But of course there is drawbacks... - it is more complicated.
Likely later, I will opensource all this, but for now - it is not quite ready to be published.
UPD1:
Original answer is a bit outdated(later I plan to update it), and I have some progress in this area.
Links to code mentioned above, already opensourced:
DI container: di1
Container for react componentns(connecting view to observables and obsrvers): rx-react-container
Starter template, for implementing isomorphic widgets, using RxJS and React, and libraries above: Reactive Widgets
About complete application(work still in progress, and documentation there is not quite good, but in general it should be clear):
Router built especially for isomophic reactive applications router1 and react components to use it router1-react
Application template with router and all libraries mentioned above: router1-app-template
React's renderToString method (for rendering components on the server) is synchronous. Therefore, any sort of async task, such as your api request, will still be pending by the time the component has rendered.
There are a couple of ways you can go about fixing this, depending on whether or not you want to fetch your data on the server or client.
If you choose to fetch the data on the server, first move your api-request logic outside of your component. Then, render your component in the callback, passing the fetched-data as a prop. It would look something like this:
response.on("end", function (err) {
var data = JSON.parse(buffer);
var markup = React.renderToString(Component({categories: data}));
});
Inside your component, you'd be able to access the data via this.props.categories.
The other option is to handle the api request on the client. You would make an AJAX request in componentDidMount, and set the component's state from the fetched data. It would look very similar to what you have now, the key difference being that your request logic would live in componentDidMount (async, called on the client) rather than componentWillMount (not async, called on the server).
You should use superagent, works really good for me, also you are missing the most important part, you should use flux to fetch data from a server, flux is the way that facebook strongly recommended, it's pretty easy to use flux architecture.
I'm currently working on an app whose database schema changes frequently. This rapid change creates a big problem for my front-end Angular code which consumes the backend JSON API (which I don't have much control over) via Restangular; take the following code for example:
<ul>
<li ng-repeat="item in items">
<h2>{{item.label}}</h2>
</li>
</ul>
There will be a lot of template tags like {{item.label}} scattered everywhere in the front-end code, so whenever the property name changes from, say "label" to "item_label", I'll need to remember where those tags are and change all of them. Of course, I could do a project wide search and replace, but that's not really ideal from an DRY stand point and it'll also be a maintenance nightmare.
My question is, does Angular (or Restangular) provide a way to map model property names to custom ones like this in Backbone?
That way, I can just have something like this
{
label: model.item_label
}
then next time when the "item_label" is changed to something else, I can just update it in this configuration object and not worry about all the references in the templates.
Thanks.
The idea with angular is that you can do whatever you want with the model. While this doesn't point you in any specific direction it does give you the opportunity to implement it in your own OO manner. Say you have an app that has a data object called ...Task a model for tasks might look like..
function Task(initJson){
this.name = initJson._name || 'New Task';
this.completed = initJson.is_completed || false;
this.doneDateTime = initJson.datetime || null;
}
Task.prototype = {
save: function(){
//do stuff with this and $http.put/post...
}
create: function(){
//do stuff with this and $http.put/post
}
//....etc
}
All of this might be wrapped up in a factory.
myApp.factory('TaskFactory',function($http){
var Tasks = []; //Or {};
//above constructor function...
//other helper methods...etc
return {
instance: Task,
collection: Tasks,
init: function(){} // get all tasks? run them through the constructor (Task), populate collection
};
})
You could then edit properties on your constructor (one place (for each data type), the only place). Although this isn't ideal if your using things like Restangular or $resource as they not equipped to be a large backing store but they just assume the properties that come across the wire, which for large, changing applications can sometimes be difficult to manage.
I ended up going with Restangular's setResponseExtractor config property based on this FAQ answer.
It looks like this:
Restangular.setResponseExtractor(function(response, operation, what, url) {
var newResponse = response;
angular.forEach(newResponse.items, function(item) {
item.label = item.item_label;
}
return newResponse;
}
I have written a large data API used in several locations outside of our web application and I would like integrate knockout into the application. It seems with knockout, you can create a model with observables. What I can't figure is a way to observe pre-existing values in our API. Is this even possible or do I need to an intermediate model to push data back and forth? That seems highly inconvenient and inefficient. Am I missing something obvious?
In the code below, I would like to observe the name attribute. I'd love suggestions on the best approach here?
EDIT: The approach preferred would be to attach observers to already existing attributes rather then writing my API around knockout or writing an additional wrapper on top of the API. This API is shared with some non-browser applications and I think that eliminates the possibility of writing the entire API using knockout without adding additional complexities. I am open to considering other frameworks that can do what I need.
myAPI.user = {
...
get name() {
return myAPI.user.object.name;
},
set name(x) {
myAPI.user.setProperty('name', x);
}
...
};
You can write a custom computed.
var VM = function() {
this.apiUserName = ko.computed({
read: function() { return myAPI.user.object.name; },
write: function(value) { return myAPI.user.setProperty('name', value); },
owner: this
});
}
Now if myAPI.user.object.name changes and you have an event for it, call valueHasMutated.
// inside your event
vm.apiUserName.valueHasMutated();