window, document and local Storage in React server side rendering - reactjs

In my React application, I am using window object , document object and localStorage.
To avoid errors, I have set it up like:
var jsdom = require("jsdom");
var doc = jsdom.jsdom("");
if (typeof localStorage === "undefined" || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./scratch');
global.localStorage = localStorage;
}
var win = doc.defaultView
console.log("document default viewwwwwwwwwwwwwwwwww", doc);
global.document = doc
global.window = win
function propagateToGlobal (window) {
for (let key in window) {
if (!window.hasOwnProperty(key)) continue
if (key in global) continue
global[key] = window[key]
}
}
propagateToGlobal(win)
But in my application, I want real window, ,real localStorage and real document to be used instead of what I have set up above.
localStorage created this directory scratch.Does that mean browser localStorage would not be used now?
Also, the console statement gives this if I try to console doc variable and is being used in place of document variable which is creating problem:
Document { location: [Getter/Setter] }
This is the script I have :
<script dangerouslySetInnerHTML={{__html:(function(w,d,s,l,i){
console.log(d.getElementsByTagName(s)[0]);
w[l]=w[l]||[];
w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';
j.async=false;
j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;
console.log("f is",f);
f.parentNode ? f.parentNode.insertBefore(j,f) : false;
})(window,document,'script','dataLayer','ID')}}/>
Here getElementByTagName returns undefined and not an element as it should. How do I fix this?

basically, JSDom and the such should only be used if you would like to fake the window and document of the browser inside NodeJS. This is valid when running tests. I've not seen node-localstorage before, but i suspect the same is true of this package also.
You certainly do not want any of those packages to run within your app when on the client (in the browser).
You haven't specified which errors you have but I can only guess you are trying to run your app in node?
I would recommend removing all of them from your app completely and seeing where you get the errors. Then tackle the errors one by one. To start with ensure you only run that code on the client by using componentDidMount or something similar.
Once the app is working on the client and on the server, you could then look at how to improve / increase the amount the is rendered on the server.

Related

Pdf Tron error " Exception error: Pdf error not found" (React App)

I'm trying to embed Pdf tron to my React application. I'm receiving this error when I'm clicking on the tab I want to filter to find the relative pdf file.
const handleFilteredDocs = (id)=>{
const filteredDoc = props.location.documents && props.location.documents.filter(doc=>{
return doc.controlId === id
})
setFileteredDoc(filteredDoc)
setPdfPath(filteredDoc[0].filePath)
WebViewer(
{
path: 'lib',
initialDoc: `lib/pdf/${pdfPath}`,
extension: "pdf"
},
viewer.current,
).then((instance) => {
const { docViewer, Annotations } = instance;
const annotManager = docViewer.getAnnotationManager();
docViewer.on('documentLoaded', () => {
const rectangleAnnot = new Annotations.RectangleAnnotation();
rectangleAnnot.PageNumber = 1;
// values are in page coordinates with (0, 0) in the top left
rectangleAnnot.X = 100;
rectangleAnnot.Y = 150;
rectangleAnnot.Width = 200;
rectangleAnnot.Height = 50;
rectangleAnnot.Author = annotManager.getCurrentUser();
annotManager.addAnnotation(rectangleAnnot);
// need to draw the annotation otherwise it won't show up until the page is refreshed
annotManager.redrawAnnotation(rectangleAnnot);
});
});
}
I'm thinking is because the ref component didn't receive in time the pdfPath state and then throw the error. I've tried to place a separate button to load the pdf with the pdfPath correctly updated and in that case worked. What can i do make it render correctly there?
this is the error I get from the console:
(index)
Value
UI version "7.3.0"
Core version "7.3.0"
Build "Mi8yMi8yMDIxfDZmZmNhOTdmMQ=="
WebViewer Server false
Full API false
Object
CoreControls.js:189 Could not use incremental download for url /lib/pdf/. Reason: The file is not linearized.
CoreControls.js:189
{message: "The file is not linearized."}
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
CoreControls.js:189 There may be some degradation of performance. Your server has not been configured to serve .gz. and .br. files with the expected Content-Encoding. See http://www.pdftron.com/kb_content_encoding for instructions on how to resolve this.
81150ece-4c18-41b0-b551-b92f332bd17f:1
81150ece-4c18-41b0-b551-b92f332bd17f:1 PDFNet is running in demo mode.
81150ece-4c18-41b0-b551-b92f332bd17f:1 Permission: read
CoreControls.js:922 Uncaught (in promise)
{message: "Exception: ↵ Message: PDF header not found. The f… Function : SkipHeader↵ Linenumber : 1139↵", type: "InvalidPDF"}
Thank you guys for any help I will get on this!
The value of "pdfPath" isn't set to "filteredDoc[0].filePath" yet after you call "setPdfPath" (it'll still be the initial state till the next render). One thing you can do is pass a callback function when using "setState" to call "WebViewer()" after "pdfPath" has been updated
https://reactjs.org/docs/react-component.html#setstate
Also there is a guide on how to add PDFtron to a React project in the following link
https://www.pdftron.com/documentation/web/get-started/react/
One thing to note, is it's does the following
useEffect(() => {
// will only run once
WebViewer()
}, [])
By doing the above, "WebViewer" is only initialized once. It might be a good idea to do something similar and use "loadDocument" (https://www.pdftron.com/documentation/web/guides/best-practices/#loading-documents-with-loaddocument) when switching between documents instead of reinitializing WebViewer each time the state changes

custom PWA version management

Is is possible to get the onload event for the pwa application in general. I meant we had implemented the a custom versioning logic in-order to keep the app version based on database field.(ie clearing the service worker cache). The issues here is the logic almost works but when ever a new version is updated in the database, then we need to clear the cache of the respective browser in-order to trigger the update. On more investigation I found that when once the pwa app is opened, it is keeping the some sort of cache image, on reopening the pwa app again won't trigger the start-up code of the app, but load app from cache.
So is it possible to get an onload sort of event for pwa ?
For testing purpose I added some alert() in the app component, but didn't fired, on reopening a pwa app
this.httpService.GetAppVersion(ver).subscribe(
res => {
if (res != null || res !== undefined) {
this.version = res.versionNumber;
ver = localStorage.getItem("appVersion");
if (ver === null || ver === undefined) {
localStorage.setItem("appVersion", "1.0");
ver = "1.0";
}
let localVersion = ver.split(".");
let incomingVersion = this.version.split(".");
let result = this.helperService.compareVersion(
localVersion,
incomingVersion
);
//alert("result : " + result);
if (result === 1) {
const snackBarRef = this.snackBar.open(
"New version available. Load New Version?",
"Yes",
{ duration: 50000000 }
);
snackBarRef.afterDismissed().subscribe(() => {
console.log("The snack-bar was dismissed");
});
snackBarRef.onAction().subscribe(() => {
localStorage.setItem("appVersion", this.version.toString());
this.helperService.Update(); // which clears the cache
setTimeout(() => {
window.location.reload(true);
}, 500);
});
}
}
},
error => {
alert("http error" + JSON.stringify(error));
}
);
at least the code in the app component's constructor will execute every time when the app is reopened after closing.
See: How to display a "new version available" for a Progressive Web App
I know this question is very old, but what I'm doing now (and I'm trying to find a better approach because I don't really like this one) is storing the version on the service worker code.
Then, when the window.onload fires, the main JavaScript code sends a message to the service worker (using postMessage()) and the service worker replies with the version number.
It's not exactly what you need, but it's an approximation.
Still, and as I said, I'm looking for a better, more maintenable approach. If I find one I'll post it here, just in case someone is searching for this (as I did).

Accessing accounts in metamask through web3.js 1.x

I want to retrieve the currently selected account in my metamask plugin through web3.js. And I want to do it dynamically, so when switched to another account, it should be printed to the UI.
I'm importing the library (beta.37) via:
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js#1.0.0-beta.37/dist/web3.min.js"></script>"
To make things more complicated:
1) In Brave web3.eth.accounts[0] would log my current address in any other site than my dApp, yet here, it returns "undefined".
2) in Chrome (same build) it would always returns undefined.
To me it is inexplicable how it can return undefined, when other dApps that are built on web3.js 0.x use that exact same code.
Consequently, I can't use the following function, to dynamically print the current address:
var accountInterval = setInterval(function() {
if (web3.eth.accounts[0] !== userAccount) {
userAccount = web3.eth.accounts[0];
}
}, 100);
In web3.js 1.x you must use getAccounts() async method, e.g. as follows:
var accounts = await web3.eth.getAccounts();
var userAccount =accounts[0]
PS: web3.eth.accounts[0] in other Dapps shows your account because they are still using the old web3.js version, very likely the one injected by Metamask

Remove item using its location or key in Firebase React

I have a simple react application and I am able to add data to it, but I am not sure how to remove/update data.
the main problem is in getting the part where I tell firebase which data to remove. how do I tell that to firebase.
I am using react.
I have been trying out different things but it's just not working
handleRemove(){
console.log('you reached handleRemove function');
var ref =firebase.database().ref('items');
ref.on('value',this.handlegetData,this.handleErrData);
['items']['KpAmo20xP6HPXc7cwjY'].remove();
//itemsRef.remove('KpAmo20xP6HPXc7cwjY');
}
Please tell me how to do this.
My firebase database looks somewhat like this
You need something like that to remove value :
handleRemove() {
return firebase.database().ref('items').child('ITEM_KEY').remove();
}
or something like that to update value :
handleUpdate() {
var updates = {};
updates['/id'] = 1;
updates['/title'] = 'Apple';
return firebase.database().ref('items').child('ITEM_KEY').update(updates);
}
(In your screenshot items is equal to firebase-test)
Here the Firebase Realtime Database documentation.

Loki JS doesn't persist data in Ionic

I'm using LokiJS to save in local storage (well, I'm trying) .
What I want to do is a ToDo app, my controller is as follows:
.controller('Dash', function($scope) {
var db = new loki('loki.json');
$scope.name="";
$scope.lname="";
var users=db.getCollection('users');
if (users==null) {
$scope.message="It's null";
var users = db.addCollection('users');
}else{
$scope.message="It's ready";
}
$scope.insert=function(namesI, lnameI){
users.insert({
name: namesI,
lname:lnameI
});
}
The issue is that everytime that I test it, the message is "It's null". Although before already I have inserted data. I mean, everytime I launch the app, the database is created.
How I can persist the data?
*I'm not using any cordova plugin.
You are not providing a loadHandler function, so you are trying to access collections before Loki is finished loading the json file. Look at this example for a clarification on how to use the autoLoadHandler.
Also bear in mind that at some stage you need to call db.saveDatabase() to persist, or else you need to provide an autoSaveInterval value when instantiating Loki.

Resources