Changes in a portion of the state for Vaadin's AbstractJavascriptComponent

I am currently working on implementing a JavaScript-based component for Vaadin that will be responsible for displaying and updating a large data set. To achieve this, I am extending AbstractJavaScriptComponent.

My goal is to keep the JavaScript side as simplistic as possible by delegating user interactions to the server through RPC calls, which then updates the shared state. Subsequently, the onStateChange function of the JS connector wrapper is triggered with the updated state, leading to the necessary DOM updates.

However, I have encountered two main challenges:

  1. I do not want to transfer the entire data set each time a small portion is modified.
  2. I aim to avoid completely rebuilding the UI every time an update occurs.

To address the second issue, I am keeping track of the previous state and comparing it to identify changes, allowing me to make targeted DOM updates when needed. However, the first problem still persists.

Should I abandon Vaadin's shared state mechanism in favor of exclusively using RPC for relaying state changes?

Update: After some testing, it seems that Vaadin's shared state approach lacks efficiency:

Whenever the component invokes getState() to update a property within the state object (even without making any actual changes), the entire state object is transmitted. As far as I can tell, the only way to circumvent this is to forego the shared state method and opt for RPC calls to communicate specific state alterations to the client.

The RPC strategy poses its own challenges that must be addressed; for instance, if you modify a value multiple times within one request/response cycle, sending multiple RPC calls is not ideal. Instead, only the final value should be transmitted akin to how the shared state mechanism responds with only the end state. One possible solution is to maintain dirty flags for individual state components or store a copy of the previous state for comparison. Nonetheless, triggering the RPC call at the culmination of request handling remains a concern. How can this be achieved?

Any insights or suggestions on this matter are greatly appreciated!

Update 2:

Vaadin 8 resolves the fundamental issue by transmitting only the altered state properties. Additionally, it no longer triggers onStateChange() on the JS connector when solely executing an RPC call (without modifying any state).

Answer №1

It has been noted that shared state synchronisation can be inefficient for components based on AbstractJavaScriptComponent. The entire state object is serialized and provided to the Javascript connector's onStateChange method whenever the connector is considered dirty. In contrast, other non-javascript components handle state updates more efficiently by only sending changes rather than the entire state object. This difference in handling of state updates can be observed at line 97 in

com.vaadin.server.LegacyCommunicationManager.java

boolean supportsDiffState = !JavaScriptConnectorState.class
            .isAssignableFrom(stateType);

The reason behind this divergence in state update handling for AbstractJavaScriptComponent-based components is not clear. Perhaps it aims to simplify the javascript connector process and eliminate the necessity of constructing a complete state object from deltas. It would be beneficial if this aspect could be addressed in upcoming versions.

One possible solution is to eliminate JavaScriptComponentState entirely and depend on server-to-client RPC for updates. Maintaining dirty flags within your server-side component or comparing old state with new state using any preferred method are feasible approaches.

To consolidate changes and transmit only one RPC call per modification, you can override

beforeClientResponse(boolean initial)
within your server-side component. This method is executed just before transmitting a response to the client, providing an opportunity to incorporate a series of RPC calls to update the client-side component.

Alternatively, overriding encodeState allows you the flexibility to send any desired JSON data to the client. You have the liberty to append a list of alterations to the base JSON object retrieved from super.encodeState, which can then be interpreted accordingly by your javascript connector's onStateChange method.

An additional tip: invoking getState() in your server-side component will mark the connector as dirty. To obtain state without triggering the dirty flag, utilize getState(false) instead.

Answer №2

After our recent conversation regarding this matter, I have devised a drop-in replacement for the AbstractJavaScriptComponent that sends state changes incrementally and incorporates some additional features. While still in its early stages of development, it shows promise.

Explore the repository here

The solution appears to be straightforward at first glance: essentially enabling differential state computation by circumventing a specific line of code within

com.vaadin.server.LegacyCommunicationManager.java
:

boolean supportsDiffState = !JavaScriptConnectorState.class
        .isAssignableFrom(stateType);

Implementing this solution proved to be complex due to the limited extensibility of Vaadin classes, resulting in the need to duplicate and re-implement 6 separate classes.

Answer №3

The functionality of Vaadin's shared state is designed to meet your needs seamlessly: upon the initial addition of a component to the DOM, the entire shared state is sent from server to client to enable display of the component. Subsequent updates only involve transferring changes. This means that when you modify a visible component's caption using

component.setCaption("new caption")
, Vaadin will transmit only the updated caption text to the client and integrate it into the existing client-side shared state for that component.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Setting up the karma ng-html2js preprocessor to locate my templates within a specific folder

Currently, I am facing an issue where I need to set the templateUrl: "partials/my-directive.html" However, I find that I have to use templateUrl: "app/partials/my-directive.html for it to be loaded by Karma. This is how my folder structure looks like (fo ...

Error in Next.js 11: Unable to loop over undefined property

Upon upgrading Next.js from version 10 to 11, I encountered an error while running npm run build: Module parse failed: Cannot read property 'forEach' of undefined File was processed with these loaders: * ./node_modules/next/dist/build/babel/loade ...

What is the best way to integrate Socket.IO into an Electron application?

I've been looking to incorporate Socket.IO into my Electron application, but the lack of documentation and examples has made it quite challenging. I would greatly appreciate if someone could provide insights on how multiple clients can communicate thr ...

What is the purpose of passing the Vuex store instance to the Vue constructor parameters?

index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {} }) app.js import Vue from 'vue' import store from &apos ...

Exploring the inner workings of self-referencing mechanics in functions

In a recent coding scenario, I encountered this situation: I attempted to define the func1() function and add several static methods to it simultaneously by passing it through the _init() function along with a hash containing properties to attach. However, ...

What is the best way to continuously run a series of functions in a loop to create a vertical news ticker effect?

I'm in the process of creating a vertical latest news ticker, and although I'm new to javascript, I'm eager to learn and build it myself. So far, I've come up with this, but I want the news cycle to restart once it reaches the end. ...

Inquiry regarding modules in Javascript/Typescript: export/import and declarations of functions/objects

I'm fresh to the realm of TypeScript and modules. I have here a file/module that has got me puzzled, and I could really use some guidance on deciphering it: export default function MyAdapter (client: Pool): AdapterType { return { async foo ( ...

What is the best way to use toggleClass on a specific element that has been extended

I have been experimenting with this code snippet for a while. The idea is that when I hover my mouse over the black box, a red box should appear. However, it doesn't seem to be working as expected. Could someone please review this script and let me k ...

Affixing a navigation bar to the top while scrolling

Does anyone know how to create a navigation bar that will "dock" to the top of the browser when scrolled to, and undock when scrolled back up? Check out my code snippet here: http://jsfiddle.net/gLQtx/ $(function() { var initPos = $('#stickyNav&apo ...

Which names can be used for HTML form tags in jQuery?

Recently, I encountered an issue related to jQuery form serialization which stemmed from naming a form tag "elements". The problem arose when using jQuery $(’form’).serialize(). Here is an example of the problematic code: <form> <input name=" ...

Yarn combined with Webpack fails to execute post-compilation tasks

When using yarn and running yarn prod, I encountered the following error: https://i.stack.imgur.com/2emFk.jpg It seems to be stuck at this particular part of the code: mix.then(() => { execSync(`npm run rtlcss ${__dirname}/Assets/css/admin.css ${__dir ...

Avoid displaying identical items when rendering a page from JSON data

I am using ajax and json to render a page. The structure of my json is as follows: {"status":"ok","rewards":[{"id":201,"points":500},{"id":202,"points":500}]}. I want to load the data using ajax only once if 'points' have duplicates in any of the ...

What is the best way to combine two JSON objects?

Item A: var item1 = { "roleid": "001", "techid": "001", "role": "WEB DEVELOPER", "tech": "JAVASCRIPT", "experience": [], "certifications": [], "gender": ["Male"], "awards": [], "min_experience_years": "4", "max_expe ...

JSX conditional rendering not behaving unexpectedly

Having difficulty with a conditional JSX statement causing an element to not display properly unless the window is resized. Please note that it works fine in development mode but does not show correctly after building. The goal is to show navigation links ...

Real-time data feeds straight from JSON

Currently, I have a JSON file that is generated dynamically and it contains match information along with a unique id. This JSON data is categorized into live, upcoming, and recent arrays. Being new to Javascript, I am unsure about the best approach to crea ...

Vue.js: API request taking too long during mounted lifecycle

I am facing an issue with API data in my Vue js project. The page loads quickly but the data from the API takes more than 5 seconds to load. Strangely, the API response appears very fast in the console. I have implemented the API in a separate file called ...

What is the procedure for matching paths containing /lang using the express middleware?

I need to target paths that contain /lang? in the URL, but I am unsure how to specifically target paths that begin with /lang? I have two routes: app.get('/lang?..... app.get('/bottle/lang?....... I want to target these routes using app.use(&a ...

What are the steps for generating and implementing shared feature files in Cucumber?

I am currently utilizing Cucumber to define some tests for the project I am working on, but as the application grows larger, I find myself in need of a more efficient structure. project | feature_files | | app1.js | | app2.js | | app3.js ...

Checking CORS permissions with a pre-flight OPTIONS request

During development, I implement a middleware called cors using the following syntax: app.use(cors({origin: 'http://localhost:8100'})); However, I have noticed that for every route request, two requests are being made as shown in the image below ...

Performing an AJAX GET request to the API after a set time interval

The API is constantly updating with live values, so I am attempting to fetch the data every second and display it on the webpage. Although I used a GET request call every N seconds using set_interval(), the values only load once and do not update with eac ...