{"id":26847760,"url":"https://github.com/ardi-n/react-redux-web-workers-sample-app","last_synced_at":"2026-05-05T08:35:02.637Z","repository":{"id":141671981,"uuid":"127281049","full_name":"ardi-n/react-redux-web-workers-sample-app","owner":"ardi-n","description":"React/Redux proof-of-concept app that utilizes Web Workers to take the load off UI thread to manage part of the state.","archived":false,"fork":false,"pushed_at":"2018-03-29T12:09:38.000Z","size":500,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-18T03:40:12.731Z","etag":null,"topics":["css-modules","parceljs","react","react-redux","web-workers"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ardi-n.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-29T11:18:36.000Z","updated_at":"2019-07-01T13:59:45.000Z","dependencies_parsed_at":"2024-07-12T03:00:09.015Z","dependency_job_id":null,"html_url":"https://github.com/ardi-n/react-redux-web-workers-sample-app","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ardi-n/react-redux-web-workers-sample-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardi-n%2Freact-redux-web-workers-sample-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardi-n%2Freact-redux-web-workers-sample-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardi-n%2Freact-redux-web-workers-sample-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardi-n%2Freact-redux-web-workers-sample-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ardi-n","download_url":"https://codeload.github.com/ardi-n/react-redux-web-workers-sample-app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardi-n%2Freact-redux-web-workers-sample-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32642241,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"online","status_checked_at":"2026-05-05T02:00:06.033Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css-modules","parceljs","react","react-redux","web-workers"],"created_at":"2025-03-30T20:30:41.890Z","updated_at":"2026-05-05T08:35:02.616Z","avatar_url":"https://github.com/ardi-n.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React/Redux proof-of-concept app that utilizes Web Workers to take the load off UI thread to manage part of the state.\n\n## [Live Example](https://ardi-n.github.io/react-redux-web-workers-sample-app/dist/index2.html)\n\n## The Problem\n\nI wanted to tackle a specific problem: is it possible to \nhandle a list of one million items in browser and manage \nits state in browser memory without contacting server for\nchunks of data? \n\nThe answer is **yes**, but with a few caveats.\nThe most important issue I came across was that as of this writing\n(March, 2018) Firefox can't handle html elements with \n`height` greater than about `17900000px` properly.\nIt instead zeroes such height.\n\nInterestingly, Chrome and Safari don't have such a low limit.\nChrome has different kind of problem - somehow a list that \nis higher than about 16776000px has all items that lie \nbelow that point hidden. DOM inspector displays them properly though.\nAlso scrolling behavior below that point breaks.\n\nThat's why I decreased row height to 16px which makes\nlist's total height 16 * 1000000. The result is lower than that Firefox's and Chrome's limits. \n\nSafari doesn't suffer from such conditions.\n\nThe app has been tested to work in Firefox, Chrome and Safari under MacOS.\n\nApp's assets are bundled using [ParcelJS](https://parceljs.org). The tool\nalso allows for seamless integration between React and [CSS Modules](https://github.com/css-modules/css-modules).\n\nParcelJS supports Web Worker script's dependency resolution and bundling out of the box. But still, when a JS module run in main thread imports something and a Worker script imports the same dependency it is bundled once for the main thread.\nThe problem is tracked [here](https://github.com/parcel-bundler/parcel/issues/758).\n\nTo be able to run `parcel index.html` in development and have bundled files updated properly a workaround is used. Worker initiation code is wrapped in\na Function constructor call (see `src/worker.js`). This way ParcelJS doesn't\ntraverse Worker's dependencies. Bundled worker file has to be recreated manually\nby running `parcel build src/worker.src.js`.\n\n## Project Architecture\n\nThe project doesn't contain many components nor handle many interactions so its directory structure is flat. There are `actions`, `components` for visual aspect, `containers` that connect them with global state and inject action creators, `reducers` that update the state and `selectors` that are used to access specific parts of the state. \n\nData used in this demonstration is generated randomly in Web Worker. Each item\nis a fictional book with a name, book genre, author name, author gender and publish date. List items can be sorted by name or author name and filtered by book genre or author gender. \n\nAdditionally books are marked in the UI if either they are horror books published on Halloween or finance books published on any last Friday.\n\n### UI Considerations\n\nNo browser could handle a list with one million rows. Each row is built out of a few elements which would lead to a few million DOM elements in memory. Gross.\n\nSeveral techniques has been employed to build this app:\n\n* First, list is scrollable. This means a wrapper element with a fixed height \nallows to see only a fragment of the whole list. This results in displaying only a chunk of dataset.\n* Chunks are small subsets of dataset. While scrolling a list, an index of a chunk that should be displayed is calculated from list's scroll position. This leads to requesting three chunks: one that is visible and two that are siblings to it. This ensures that window is filled with rows.\n* The actual scroll event listener is debounced - it's called when scrolling has stopped for a few dozens of milliseconds. This improves performance and unnecessary calls to get dataset chunks are avoided.\n* When scroll event listener is called, an action is issued only if just calculated index of chunk is different from current index.\n* UI elements that correspond to chunks have keys which helps React to decide if they shouls stay or be removed.\n\nThese are other, non-performance related UI things:\n\n* CSS Modules are used to nicely separate component's styles from global context.\n* No UI framework is used. Layout is simply built using flexible containers. List is `position: relative` which allows to `position: absolute` rendered list chunks.\n\n### State Implementation\n\nState's shape follows good practices and is split between `entities` and `ui`.\nEntities contain normalized domain objects and ui has necessary data persisted for re-use by Redux-powered containers.\n\nRedux state exists in two parts. One store that contains lightweight\ndata necessary for UI components lives in main context. The other that deals with big data lives in worker context. \n\nMessages posted to Worker are typical Redux actions. Worker's store handles them\nby running the same reducers used for main store but aware of context. In result Worker posts back a message with action for the main context that contains necessary chunks of data to update the list.\n\nIf some data is duplicated between stores, selectors act the same. In specific circumstances like for `getListItemsCount` the selector checks if it's called in Worker context. If so, it counts items stored physically there. Otherwise, it uses a cached value stored in main context.\n\n#### Reselect\n\nInitially there was a plan to use [Reselect](https://github.com/reactjs/reselect). But as it turned out its caching mechanism led to quickly growing memory consumption when selecting specific chunks of whole dataset. So a dumb version of `createSelector` was provided that can just compose other selectors. This way selecting chunks of data is performed every time in Worker in non-blocking fashion.\n\n## Running Locally\n\nAfter cloning the repository please run `npm install` and then `npm run start-dev`.\n\n## About the author\n\nMy name is Adrian Nowicki. You can contact me through \n[LinkedIn](https://www.linkedin.com/in/adriannowicki/)\nand [Twitter](https://twitter.com/MeNowicki). \nSome of my work is published on [Github](https://github.com/ardi-n).\n\nBy the way, I'm the founder of \n[Livewallpaper.io](https://www.livewallpaper.io),\na place for awesome Android phone wallpapers. If you wonder how to turn\na gif or an mp4 into a live wallpaper, \nyou can find the answer [here](https://www.livewallpaper.io/how-it-works).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fardi-n%2Freact-redux-web-workers-sample-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fardi-n%2Freact-redux-web-workers-sample-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fardi-n%2Freact-redux-web-workers-sample-app/lists"}