ReactJs in CEFSharp save state and restore at startup - reactjs

I am currently writing a ReactJS UI for my c# Project. It will run in a CEFSharp control.
Now I try to save the state of a Reacj object whenever the state is changed.
When the c# programm is (re-)started the saved state should be restored in the page.
What is working so far:
Transmitting the state and saving it in c# is working:
exportState(){
if(navigator.userAgent === 'CEF')
{
let jsonstate = JSON.stringify(this.state.Fenster);
window.nativeHost.kontrolstate(jsonstate);
}
}
Fenster is an array of an own defined object.
To be able to push the saved state back to the react component I have created an ref:
<Kontrolle ref={(kont) => {window.Kontrolle = kont}} />
So I can call the procedures of component Kontrolle via a javascript call in CEFSharp.
To restore the state I call this procedure:
jsontostate(jsonstring){
var fen = jsonstring;
let fenster = this.state.Fenster;
for (var i=0; i<fen.length;i++) {
var f = fen[i];
let index = fenster.findIndex(x => x.id === f.id);
fenster[index].colum = f.colum;
fenster[index].offen = f.offen;
fenster[index].sort = f.sort;
}
this.setState({Fenster: fenster});
this.render();
}
It looks like working perfecly.
The state is updated correctly.
Also when I check the state in the debug console of CEFSharp it looks correctly.
There is also no error displayed in the console.
What is not working:
The state has influence to the page.
After calling the procedure the page is not rendered newly.
So the state and page are not in line.
I already have tried to force a render.
Without success.
Where is my mistake?
Can someone give me a hint?

Found the reason by myself.
I did implement the component Kontrolle twice.
One with ref one without ref.
I checked the rendered UI on the wrong implementation.
So, my own mistake.
The code I have posted work fine.
Thanks to all.

Related

react manage query string called data

I don't know how to manage query string to react.
I made component class and it is composed of 3 other components.
It is not show data first time. Users have to select or click but
ton.
It is work well.
But I received a new feature. ;(
When users connect my site who copied url, the page has to show data immediately.
So I added query string. But I don't know when I call function.
I installed query-string.
I tried to use 'shouldComponentUpdate' function, but it was not work.
shouldComponentUpdate(nextProps, nextState) {
if (this.props.location.search.ids !== nextProps.location.search.ids) {
// call some function....
}
return true;
}
for example,
Users connect localhost:3000/my/home
It's ok.
But users connect localhost:3000/my/home?ids=1
It's not ok.
Summary.
I want to show data immediately when user connect to the site by query-string.
to fetch data, the most common way to call api is calling in componentDidMount.
https://reactjs.org/docs/faq-ajax.html
if you are using react-router for your app, you can easily get query string with following feature of react-router .
https://reacttraining.com/react-router/web/example/query-parameters
and then pass query string to your api.
I added componentDidMount and call myfunction.
componentDidMount(){
const query = queryString.parse(this.props.location.search);
if(query.ids !== 'undefined'){
let slice_ids = [];
slice_ids = query.ids.split(',');
if(slice_ids.length > 0){
this.myfunction(1);
}
}
}
Users can access the url.
Thanks #gnujoow

How to display progress to user during long running process in React

I am building an app where a user provides a file and some parameters to then perform a long running task. I have all of that working. What is not working is showing the user the current progress of processing. I have a simple CodePen set up to illustrate.
In the Pen, I have a button that runs a task in a while loop. If I am looking at the console, I can see the progress printing out as we step through the loop. However, the state isn't updating until the loop is done, so in the UI the progress jumps from 0 to 5 without displaying the intermediate values. Here I am simulating the task with the sleep function, I do not actually use the sleep function in my app.
I've done some research and I know this has to do with setState being asynchronous and with React batching updates together to be more efficient with rendering the UI.
With that being said, I am wondering what the best way to display progress to the user would be. Using React's state doesn't work, and I've tried directly writing to the DOM but that wasn't working (and it didn't seem like a clean way to do it). Do I need to use some additional library to do this or is there something I am missing? I was considering moving this to a separate process and then communicating the progress back to the app, but wouldn't I run into the same issue of the UI not updating?
Also potentially important, I am using the while loop because I am using a generator, so I know I won't receive too many progress updates because yield runs each percentage point from 0 to 100. It is also easy for me to remove the generator/yield part if that would be better.
My code is in CodePen as well as below:
---HTML---
<div id="app"></app>
---JSX---
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
progress: 0
};
this.doTask = this.doTask.bind(this);
this.sleep = this.sleep.bind(this);
}
sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
doTask() {
let count = 0;
while(count<5) {
count++;
console.log(count);
this.setState({
progress: count
});
this.sleep(500);
}
}
render() {
return <div>
<button onClick={this.doTask}>Do Task</button>
<div>Progress: {this.state.progress}</div>
</div>;
}
}
/*
* Render the above component into the div#app
*/
React.render(<Application />, document.getElementById('app'));
This is a recurring issue in development, so I hope this question and solutions helps you out: Calling setState in a loop only updates state 1 time.
I would also take a look at https://jsbin.com/kiyaco/edit?js,output where an alternate form of this.setState is used. It essentially passed in a function which has access to the current state.
What I ended up doing was creating a background process (aka a hidden window because I'm using electron) that basically acts as a server. The information for my long running process is sent to the background process via a websocket and the progress information is sent back to my main component also via a websocket. Updating the state from a loop seems to me to be more intuitive, but running my code in the background doesn't freeze up the UI and now I get my desired behavior.
I have the same issue and used a workaround. For some reason, when using setTimeout() the page does the setState() processing correctly. It remembered me of runLater in JavaFX.
So this is a workaround I used:
// a wrapper function for setState which uses `Promise` and calls `setTimeout()`
setStatePromise = (state) => new Promise(resolve => {
this.setState(state, () => {
setTimeout(() => resolve(), 1);
});
});
Now you can call this wrapper instead. But you'll need to use async functions:
async doTask() {
let count = 0;
while(count<5) {
count++;
console.log(count);
await this.setStatePromise({
progress: count
});
this.sleep(500);
}
}

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.

window, document and local Storage in React server side rendering

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.

Publish/Subscribe not working automatically when data added to the mongodb

I have the following publisher and subscriber code.
It works for the first time when the app starts, but when I try to insert data directly into the Mongo database, it will not automatically update the user screen or I don't see the alert popping.
Am I missing something?
Publish
Meteor.publish('userConnections', function(){
if(!this.userId){
return;
}
return Connections.find({userId: this.userId});
})
Subscribe
$scope.$meteorSubscribe('userConnections').then(function () {
var userContacts = $scope.$meteorCollection(Connections);
alert("subscriber userConnections is called");
if (userContacts && userContacts[0]) {
....
}
}, false);
First off, if you are not using angular-meteor 1.3 you should be. The API has changed a lot. $meteorSubscribe has been deprecated!
To directly answer your question, $meteorSubscribe is a promise that gets resolved (only once) when the subscription is ready. So, it will only ever be called once. If you look at the documentation for subscribe you'll see how to make the binding "reactive", by assigning it to a scope variable. In your case it would be something like:
$scope.userContacts = $scope.$meteorCollection(Connections);
Doing it this way, when the collection gets updated, the $scope.userContacts should get updated as well.

Resources