From 6d905d8ab24c74ad65329293b2a6f955e67a03d7 Mon Sep 17 00:00:00 2001 From: "Rahul A. Krishna" Date: Wed, 21 Feb 2024 21:47:16 +0530 Subject: [PATCH] recursion in react --- .gitignore | 14 +- ...a10216bb97d1cad9f83c579759ec9f3094d845815f | 230 ------------ _assets/.DS_Store | Bin 6148 -> 0 bytes _includes/.DS_Store | Bin 6148 -> 0 bytes _layouts/.DS_Store | Bin 6148 -> 0 bytes _posts/2024-02-10-arc-search.markdown | 2 +- _posts/2024-02-21-recursion-in-react.markdown | 124 +++++++ _site/feed.xml | 347 ++++++------------ _site/index.html | 12 + _site/notes/2024/02/10/arc-search.html | 10 +- images/budgeting-tool/.DS_Store | Bin 6148 -> 0 bytes .../recursion-in-react/javascript-result.png | Bin 0 -> 3657 bytes images/recursion-in-react/react-result.png | Bin 0 -> 7360 bytes .../recursion-in-react/real-life-example.png | Bin 0 -> 67604 bytes 14 files changed, 275 insertions(+), 464 deletions(-) delete mode 100644 .jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/0e/42ece69f0fcb8d73a940a10216bb97d1cad9f83c579759ec9f3094d845815f delete mode 100644 _assets/.DS_Store delete mode 100644 _includes/.DS_Store delete mode 100644 _layouts/.DS_Store create mode 100644 _posts/2024-02-21-recursion-in-react.markdown delete mode 100644 images/budgeting-tool/.DS_Store create mode 100644 images/recursion-in-react/javascript-result.png create mode 100644 images/recursion-in-react/react-result.png create mode 100644 images/recursion-in-react/real-life-example.png diff --git a/.gitignore b/.gitignore index ce8754b..59308ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,14 @@ .DS_Store -.jekyll-cache/* \ No newline at end of file +_site/ +.sass-cache/ +.jekyll-cache/ +.jekyll-metadata +# Ignore folders generated by Bundler +.bundle/ +vendor/./.DS_Store +./_assets/.DS_Store +./_includes/.DS_Store +./_layouts/.DS_Store +./images/.DS_Store +./images/budgeting-tool/.DS_Store +./images/recursion-in-react/.DS_Store diff --git a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/0e/42ece69f0fcb8d73a940a10216bb97d1cad9f83c579759ec9f3094d845815f b/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/0e/42ece69f0fcb8d73a940a10216bb97d1cad9f83c579759ec9f3094d845815f deleted file mode 100644 index c39823e..0000000 --- a/.jekyll-cache/Jekyll/Cache/Jekyll--Converters--Markdown/0e/42ece69f0fcb8d73a940a10216bb97d1cad9f83c579759ec9f3094d845815f +++ /dev/null @@ -1,230 +0,0 @@ -I"át

Premise

- -
- -

Untitled

- -

n order to visualize geospatial data, we are employing the google-map-react library. However, we have encountered a performance issue when rendering a substantial volume of data points. This issue manifests as a temporary unresponsiveness of the page, followed by a noticeable slowdown in subsequent operations. These symptoms suggest the presence of a memory leak.

- -

Untitled

- -

This is the code used. The only cleanup happening was setting data to null.

- -

The issue

- -
- -

There are three issues present here.

- -
    -
  1. Destroying Google Maps instance never frees up memory. The persistent memory leak issue within the Google Maps JavaScript Library has been a significant concern for developers. Upon visiting the page, approximately 600MB of memory remains unfreed, leading to potential performance degradation. This problem was initially documented in Google’s Bug Tracker in 2011, and the most recent update was in February 2023, indicating that this issue has persisted for over a decade.
  2. -
  3. A line consists of three drawings. In an optimal scenario, the ‘trip line’ should be represented by a single stroke. However, in the current implementation, we are generating three separate drawings: one Polyline and two Markers. It has been observed that the process of rendering the Markers is particularly resource-intensive, leading to a noticeable decrease in performance.
  4. -
  5. The Polylines could be made into an Overlay. In lieu of instantiating classes within the Google Maps environment, we propose the development of a distinct Polyline component. This approach would allow us to isolate and effectively manage any associated memory-related issues within this separate component.
  6. -
- -

The fix for Google Maps memory leak

- -
- -

Untitled

- -

But we can try to Introduce a function to manually delete all of Google Map’s event listeners.

- -
// Helper function: Removes all event listeners registered with Google's addDomListener function,
-// including from __e3_ properties on target objects.
-function removeAllGoogleListeners(target, event) {
-  var listeners = target["__e3_"];
-  if (!listeners) {
-    console.warn(
-      "Couldn't find property __e3_ containing Google Maps listeners. Perhaps Google updated the Maps SDK?"
-    );
-    return;
-  }
-  var evListeners = listeners[event];
-  if (evListeners) {
-    for (var key in evListeners) {
-      if (evListeners.hasOwnProperty(key)) {
-        google.maps.event.removeListener(evListeners[key]);
-      }
-    }
-  }
-}
-
-// Removes all DOM listeners for the given target and event.
-function removeAllDOMListeners(target, event) {
-  var listeners = target["__listeners_"];
-  if (!listeners || !listeners.length) {
-    return;
-  }
-
-  // Copy to avoid iterating over array that we mutate via removeEventListener
-  var copy = listeners.slice(0);
-  for (var i = 0; i < copy.length; i++) {
-    target.removeEventListener(event, copy[i]);
-  }
-}
-
-// Shim addEventListener to capture and store registered event listeners.
-var addEventListener = EventTarget.prototype.addEventListener;
-EventTarget.prototype.addEventListener = function () {
-  var eventName = arguments[0];
-  var listener = arguments[1];
-  if (!this["__listeners_"]) {
-    this.__listeners_ = {};
-  }
-  var listeners = this.__listeners_;
-  if (!listeners[eventName]) {
-    listeners[eventName] = [];
-  }
-  listeners[eventName].push(listener);
-  return addEventListener.apply(this, arguments);
-};
-var removeEventListener = EventTarget.prototype.removeEventListener;
-EventTarget.prototype.removeEventListener = function () {
-  var eventName = arguments[0];
-  var listener = arguments[1];
-  if (this["__listeners_"] && this.__listeners_[eventName]) {
-    // Loop because the same listener may be added twice with different
-    // options, and because our simple addEventListener shim doesn't
-    // check for duplicates.
-    while (true) {
-      var i = this.__listeners_[eventName].indexOf(listener);
-      if (i === -1) {
-        break;
-      }
-      this.__listeners_[eventName].splice(i, 1);
-    }
-  }
-  return removeEventListener.apply(this, arguments);
-};
-
-// After you remove the Google Map from the DOM, call this function to completely free the object.
-export default function destroyGoogleMaps(window) {
-  removeAllGoogleListeners(window, "blur");
-  removeAllGoogleListeners(window, "resize");
-  removeAllGoogleListeners(document, "click");
-  removeAllGoogleListeners(document, "keydown");
-  removeAllGoogleListeners(document, "keypress");
-  removeAllGoogleListeners(document, "keyup");
-  removeAllGoogleListeners(document, "MSFullscreenChange");
-  removeAllGoogleListeners(document, "fullscreenchange");
-  removeAllGoogleListeners(document, "mozfullscreenchange");
-  removeAllGoogleListeners(document, "webkitfullscreenchange");
-  // ASSUMPTION: No other library registers global resize and scroll event listeners! If this is not true, then you'll need to add logic to avoid removing these.
-  removeAllDOMListeners(window, "resize");
-  removeAllDOMListeners(window, "scroll");
-}
-
- -

Credit to this commenter: https://issuetracker.google.com/issues/35821412#comment53

- -

This resolves the memory issue to an extent.

- -

The flow observed is. Landing page → Page with Trips View → Page with another Google Map → Page without Google Map

- -

The flow observed is. Landing page → Page with Trips View → Page with another Google Map → Page without Google Map

- -

In Prod and Staging, the Page without Google Maps hogs up memory while introducing the memory cleanup in dev shows us that it requires way less memory!

- -

The fix for three drawings

- -
- -

This one happens to be very simple. While creating a Polyline, just specify an icon and set the repeat value as 100%.

- -
new google.maps.Polyline({
-  strokeColor: props.color,
-  geodesic: true,
-  strokeWeight: 3,
-  icons: [
-    {
-      icon: {
-        path: google.maps.SymbolPath.CIRCLE,
-      },
-      repeat: "100%",
-    },
-  ],
-});
-
- -

We can even make the icon a SymbolPath.FORWARD_PATH (Reference: https://developers.google.com/maps/documentation/javascript/reference/marker#SymbolPath) indicating the trip direction as well!

- -

Making the Polylines an Overlay

- -
- -

Now all of the computations happen inside the onGoogleApiLoaded method of google-map-react.

- -

Untitled

- -

First thing, we make this function do nothing but set a state called map. This is for us to later set the PolyLine on to the map.

- -

Polyline.js

- -
import { useState } from "react";
-
-import useDeepCompareEffect from "use-deep-compare-effect";
-
-function pathsDiffer(path1, path2) {
-  if (path1.getLength() != path2.length) return true;
-  for (const [i, val] of path2.entries())
-    if (path1.getAt(i).toJSON() != val) return true;
-  return false;
-}
-
-export default function PolyLine(props) {
-  const [polyline, setPolyline] = useState(null);
-
-  useDeepCompareEffect(() => {
-    // Create polyline after map initialized.
-    if (!polyline && props.map) {
-      setPolyline(
-        new google.maps.Polyline({
-          strokeColor: props.color,
-          geodesic: true,
-          strokeWeight: 3,
-          icons: [
-            {
-              icon: {
-                path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
-              },
-              repeat: "100%",
-            },
-          ],
-        })
-      );
-    }
-
-    // Synchronize map polyline with component props.
-    if (polyline && polyline.getMap() != props.map) polyline.setMap(props.map);
-    if (polyline && pathsDiffer(polyline.getPath(), props.path))
-      polyline.setPath(props.path);
-
-    return () => {
-      // Cleanup: remove line from map
-      if (polyline) polyline.setMap(null);
-    };
-  }, [props, polyline]);
-
-  return null;
-}
-
- -

Now inside the component,

- -

Untitled

- -

Finally, as a sibling to GoogleMapReact we introduce the Polyline component.

- -

Untitled

- -

Final Result

- -
- -

Maps look way more meaningful

- -

Untitled

- -

The memory consumption which went from 500MB to 367MB after memory cleanup, went down to 140MB after removing the marker drawings!

-:ET \ No newline at end of file diff --git a/_assets/.DS_Store b/_assets/.DS_Store deleted file mode 100644 index 6da651cf8a4f37ff679819ba0508b5de1a905983..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~!D<^Z5Qay#ldK5=A6ilKitJb7dE zB+2w}Y!kA<5JNs6XL?{}T{G2#!sf=VBd7=UUgPUNd}k zu(w#$gQqWE9=`8=%TKlWZWl=kAF{O#uh(*c$`XR}c&u}yM~HLICg5bGJ){ybGW#UpH649Ke(=#GAs{v@RdnS!9I8p0U6a_IO5j+l{J!PKbL!))o)g;E2C_ zTz9)QSM_Sw^u>o6N5JgB*y80R>-`(cs2Ng$R3H^d1yX^3t^j+sY&vtym`AN}RM<1tN sTj}@oFJrBhGYk#^oTwFF9@SNiS=R!4N24=ubYdO^q)S>V@EZzz0v9hR>Hq)$ diff --git a/_layouts/.DS_Store b/_layouts/.DS_Store deleted file mode 100644 index 427b5efeee283ba9ec476e3f3641dcfb100821f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRW;41Eq2w1Pzi8vZ=yH@KnB(16zBu!QWdiv%^K1Bstw7^vrUv(V}=sXc*im3jc9jlA_Ka2 z`xxUEubATJ{*`#4?*#X>k0>sRay%-^5##k``Q(v5GOS2=B)Nj@4GbIvkr&&YPxWc+hlF1jF30PRKhHNvXt?Dt5$> zlum!JxZJQ#n9?D3_z;^}?1Un5cGeFu9Fiw=>kK#p%M5I#%f9yi^Y-)qa*|&;1J1y| zVn8~>tKoo;WWBZVaN27F^@ggVadpB)3J0+jGge#iAvFs9K?lU#uue!1#eW1M4Q`x) HKV{$>;tz6g diff --git a/_posts/2024-02-10-arc-search.markdown b/_posts/2024-02-10-arc-search.markdown index d9a3854..beaf056 100644 --- a/_posts/2024-02-10-arc-search.markdown +++ b/_posts/2024-02-10-arc-search.markdown @@ -13,7 +13,7 @@ tags: [browsers, ux] Here is what Arc Search has to say about Arc Search! -
+
### Basic Stuff it does diff --git a/_posts/2024-02-21-recursion-in-react.markdown b/_posts/2024-02-21-recursion-in-react.markdown new file mode 100644 index 0000000..f569bed --- /dev/null +++ b/_posts/2024-02-21-recursion-in-react.markdown @@ -0,0 +1,124 @@ +--- +layout: post +title: "Recursion in React" +author: "Rahul Krishna" +date: 2024-02-21 11:15:00 +0530 +categories: [notes] +tags: [javascript, react] +--- + +### TLDR; + +--- + +TIL that you can have recursive components in React! + + +
+So while thinking in React, it may not immediately occur that you can call a **parent** inside the **child!** But it is possible + +### Consider a Data Structure like this: + +--- + +```jsx +const comments = [ + { + content: "Comment 1", + level: 0, + comments: [ + { + content: "Comment 1 > 1", + level: 1, + comments: [ + { + content: "Comment 1 > 1 > 1", + level: 2, + comments: [], + }, + ], + }, + { + content: "Comment 1 > 2", + level: 1, + comments: [], + }, + ], + }, + { + content: "Comment 2", + level: 0, + comments: [], + }, +]; +``` + +### Doing this in Javascript + +--- + +```jsx +function displayComments(comments) { + return comments.reduce((acc, comment) => { + const prefix = Array(comment.level) + .fill("|") + .reduce((acc, item) => `${acc} ${item}`, ""); + + const moreComments = displayComments(comment.comments); + + const stringToReturn = `${prefix} ${comment.content} \n ${moreComments}`; + return `${acc} ${stringToReturn}`; + }, ""); +} +``` + +Result: + +![Javascript Result](/images/recursion-in-react/javascript-result.png) + +### Doing this in React + +--- + +```jsx +function Comment({ comment }) { + const prefix = Array(comment.level) + .fill("|") + .reduce((acc, item) => `${acc} ${item}`, ""); + return ( +
+ {prefix} {comment.content} + +
+ ); +} + +export default function Comments({ comments }) { + return comments.map((comment) => { + return ; + }); +} +``` + +Result: + +![React Result](/images/recursion-in-react/react-result.png) + +### Actual example of rendering a comment tree + +--- + +It’s unlikely we’ll be using `|` prefixes when actually building a comment tree. We’ll more likely be playing around with `padding` and `margin`. + +Here’s a code example of actual comment tree rendering in React with TailwindCSS: [https://github.com/rahulakrishna/hackrmn/blob/master/src/app/[storylist]/comments/[commentid]/comment-block.js](https://github.com/rahulakrishna/hackrmn/blob/master/src/app/%5Bstorylist%5D/comments/%5Bcommentid%5D/comment-block.js) + +![Untitled](/images/recursion-in-react/real-life-example.png) + +### References + +--- + +- Thinking in React: [https://react.dev/learn/thinking-in-react](https://react.dev/learn/thinking-in-react) +- hackrmn repo: [https://github.com/rahulakrishna/hackrmn/tree/master](https://github.com/rahulakrishna/hackrmn/tree/master) diff --git a/_site/feed.xml b/_site/feed.xml index 9e066d5..e77da3e 100644 --- a/_site/feed.xml +++ b/_site/feed.xml @@ -1,10 +1,123 @@ -Jekyll2024-02-21T09:31:07+05:30http://localhost:4000/feed.xmlField NotesHello I'm a Principal Software Engineer at Bridgestone Americas. I occasionally convert my Notion Docs to markdown and publish them here.Arc Search2024-02-10T11:15:00+05:302024-02-10T11:15:00+05:30http://localhost:4000/notes/2024/02/10/arc-search<h3 id="what-is-it">What is it?</h3> +Jekyll2024-02-21T21:46:35+05:30http://localhost:4000/feed.xmlField NotesHello I'm a Principal Software Engineer at Bridgestone Americas. I occasionally convert my Notion Docs to markdown and publish them here.Recursion in React2024-02-21T11:15:00+05:302024-02-21T11:15:00+05:30http://localhost:4000/notes/2024/02/21/recursion-in-react<h3 id="tldr">TLDR;</h3> + +<hr /> + +<p>TIL that you can have recursive components in React!</p> + +<aside> +💡 React uses one-way data flow, passing data down the component hierarchy from parent to child component +</aside> +<p><br /> +So while thinking in React, it may not immediately occur that you can call a <strong>parent</strong> inside the <strong>child!</strong> But it is possible</p> + +<h3 id="consider-a-data-structure-like-this">Consider a Data Structure like this:</h3> + +<hr /> + +<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">comments</span> <span class="o">=</span> <span class="p">[</span> + <span class="p">{</span> + <span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Comment 1</span><span class="dl">"</span><span class="p">,</span> + <span class="na">level</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> + <span class="na">comments</span><span class="p">:</span> <span class="p">[</span> + <span class="p">{</span> + <span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Comment 1 &gt; 1</span><span class="dl">"</span><span class="p">,</span> + <span class="na">level</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="na">comments</span><span class="p">:</span> <span class="p">[</span> + <span class="p">{</span> + <span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Comment 1 &gt; 1 &gt; 1</span><span class="dl">"</span><span class="p">,</span> + <span class="na">level</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> + <span class="na">comments</span><span class="p">:</span> <span class="p">[],</span> + <span class="p">},</span> + <span class="p">],</span> + <span class="p">},</span> + <span class="p">{</span> + <span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Comment 1 &gt; 2</span><span class="dl">"</span><span class="p">,</span> + <span class="na">level</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> + <span class="na">comments</span><span class="p">:</span> <span class="p">[],</span> + <span class="p">},</span> + <span class="p">],</span> + <span class="p">},</span> + <span class="p">{</span> + <span class="na">content</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Comment 2</span><span class="dl">"</span><span class="p">,</span> + <span class="na">level</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> + <span class="na">comments</span><span class="p">:</span> <span class="p">[],</span> + <span class="p">},</span> +<span class="p">];</span> +</code></pre></div></div> + +<h3 id="doing-this-in-javascript">Doing this in Javascript</h3> + +<hr /> + +<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">displayComments</span><span class="p">(</span><span class="nx">comments</span><span class="p">)</span> <span class="p">{</span> + <span class="k">return</span> <span class="nx">comments</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">comment</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> + <span class="kd">const</span> <span class="nx">prefix</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">level</span><span class="p">)</span> + <span class="p">.</span><span class="nx">fill</span><span class="p">(</span><span class="dl">"</span><span class="s2">|</span><span class="dl">"</span><span class="p">)</span> + <span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s2">`</span><span class="p">${</span><span class="nx">acc</span><span class="p">}</span><span class="s2"> </span><span class="p">${</span><span class="nx">item</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="dl">""</span><span class="p">);</span> + + <span class="kd">const</span> <span class="nx">moreComments</span> <span class="o">=</span> <span class="nx">displayComments</span><span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">comments</span><span class="p">);</span> + + <span class="kd">const</span> <span class="nx">stringToReturn</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">prefix</span><span class="p">}</span><span class="s2"> </span><span class="p">${</span><span class="nx">comment</span><span class="p">.</span><span class="nx">content</span><span class="p">}</span><span class="s2"> \n </span><span class="p">${</span><span class="nx">moreComments</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> + <span class="k">return</span> <span class="s2">`</span><span class="p">${</span><span class="nx">acc</span><span class="p">}</span><span class="s2"> </span><span class="p">${</span><span class="nx">stringToReturn</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> + <span class="p">},</span> <span class="dl">""</span><span class="p">);</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>Result:</p> + +<p><img src="/images/recursion-in-react/javascript-result.png" alt="Javascript Result" /></p> + +<h3 id="doing-this-in-react">Doing this in React</h3> + +<hr /> + +<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">Comment</span><span class="p">({</span> <span class="nx">comment</span> <span class="p">})</span> <span class="p">{</span> + <span class="kd">const</span> <span class="nx">prefix</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">comment</span><span class="p">.</span><span class="nx">level</span><span class="p">)</span> + <span class="p">.</span><span class="nx">fill</span><span class="p">(</span><span class="dl">"</span><span class="s2">|</span><span class="dl">"</span><span class="p">)</span> + <span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">acc</span><span class="p">,</span> <span class="nx">item</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="s2">`</span><span class="p">${</span><span class="nx">acc</span><span class="p">}</span><span class="s2"> </span><span class="p">${</span><span class="nx">item</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span> <span class="dl">""</span><span class="p">);</span> + <span class="k">return</span> <span class="p">(</span> + <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span> + <span class="si">{</span><span class="nx">prefix</span><span class="si">}</span> <span class="si">{</span><span class="nx">comment</span><span class="p">.</span><span class="nx">content</span><span class="si">}</span> + <span class="p">&lt;</span><span class="nc">Comments</span> <span class="na">comments</span><span class="p">=</span><span class="si">{</span><span class="nx">comment</span><span class="p">.</span><span class="nx">comments</span><span class="si">}</span> <span class="p">/&gt;</span> + <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> + <span class="p">);</span> +<span class="p">}</span> + +<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">Comments</span><span class="p">({</span> <span class="nx">comments</span> <span class="p">})</span> <span class="p">{</span> + <span class="k">return</span> <span class="nx">comments</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">comment</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span> + <span class="k">return</span> <span class="p">&lt;</span><span class="nc">Comment</span> <span class="na">comment</span><span class="p">=</span><span class="si">{</span><span class="nx">comment</span><span class="si">}</span> <span class="p">/&gt;;</span> + <span class="p">});</span> +<span class="p">}</span> +</code></pre></div></div> + +<p>Result:</p> + +<p><img src="/images/recursion-in-react/react-result.png" alt="React Result" /></p> + +<h3 id="actual-example-of-rendering-a-comment-tree">Actual example of rendering a comment tree</h3> + +<hr /> + +<p>It’s unlikely we’ll be using <code class="language-plaintext highlighter-rouge">|</code> prefixes when actually building a comment tree. We’ll more likely be playing around with <code class="language-plaintext highlighter-rouge">padding</code> and <code class="language-plaintext highlighter-rouge">margin</code>.</p> + +<p>Here’s a code example of actual comment tree rendering in React with TailwindCSS: <a href="https://github.com/rahulakrishna/hackrmn/blob/master/src/app/%5Bstorylist%5D/comments/%5Bcommentid%5D/comment-block.js">https://github.com/rahulakrishna/hackrmn/blob/master/src/app/[storylist]/comments/[commentid]/comment-block.js</a></p> + +<p><img src="/images/recursion-in-react/real-life-example.png" alt="Untitled" /></p> + +<h3 id="references">References</h3> + +<hr /> + +<ul> + <li>Thinking in React: <a href="https://react.dev/learn/thinking-in-react">https://react.dev/learn/thinking-in-react</a></li> + <li>hackrmn repo: <a href="https://github.com/rahulakrishna/hackrmn/tree/master">https://github.com/rahulakrishna/hackrmn/tree/master</a></li> +</ul>Rahul KrishnaTLDR;Arc Search2024-02-10T11:15:00+05:302024-02-10T11:15:00+05:30http://localhost:4000/notes/2024/02/10/arc-search<h3 id="what-is-it">What is it?</h3> <hr /> <p>Here is what Arc Search has to say about Arc Search!</p> -<div style="text-align: center;"><img src="/images/arc-search/Untitled.png" style="max-width: 250px;" /></div> +<div style="text-align: center;"><img src="/images/arc-search/javascript-result.png" style="max-width: 250px;" /></div> <h3 id="basic-stuff-it-does">Basic Stuff it does</h3> @@ -880,232 +993,4 @@ content/post/2023-10-20-some-miscellaneous-git-facts.markdown | 40 +++++++++++++ <hr /> -<p>Julia Evans’ Blog Article: <a href="https://jvns.ca/blog/2023/10/20/some-miscellaneous-git-facts/">https://jvns.ca/blog/2023/10/20/some-miscellaneous-git-facts/</a></p>Rahul KrishnaWhat is a Stash?Memory Leak in Google Maps2023-10-21T00:48:44+05:302023-10-21T00:48:44+05:30http://localhost:4000/notes/2023/10/21/memory-leak-in-google-maps<h3 id="premise">Premise</h3> - -<hr /> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2F0a0376ef-1fed-43b9-b795-a0838c2dc18a%2FUntitled.png?table=block&amp;id=5dbb1e64-43ed-4918-8607-981ca6a374a1&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=2000&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>In order to visualize geospatial data, we are employing the google-map-react library. However, we have encountered a performance issue when rendering a substantial volume of data points. This issue manifests as a temporary unresponsiveness of the page, followed by a noticeable slowdown in subsequent operations. These symptoms suggest the presence of a memory leak.</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2F0e323202-b790-4d19-9f30-e80445bcea0f%2FUntitled.png?table=block&amp;id=30bf63d9-45c4-4bbe-b5d0-b6d31ee4bff2&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=770&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>This is the code used. The only cleanup happening was setting <code class="language-plaintext highlighter-rouge">data</code> to <code class="language-plaintext highlighter-rouge">null</code>.</p> - -<h3 id="the-issue">The issue</h3> - -<hr /> - -<p>There are three issues present here.</p> - -<ol> - <li><strong>Destroying Google Maps instance never frees up memory.</strong> The persistent memory leak issue within the Google Maps JavaScript Library has been a significant concern for developers. Upon visiting the page, approximately 600MB of memory remains unfreed, leading to potential performance degradation. This problem was initially documented in Google’s Bug Tracker in 2011, and the most recent update was in February 2023, indicating that this issue has persisted for over a decade.</li> - <li><strong>A line consists of three drawings.</strong> In an optimal scenario, the ‘trip line’ should be represented by a single stroke. However, in the current implementation, we are generating three separate drawings: one Polyline and two Markers. It has been observed that the process of rendering the Markers is particularly resource-intensive, leading to a noticeable decrease in performance.</li> - <li><strong>The <code class="language-plaintext highlighter-rouge">Polylines</code> could be made into an Overlay.</strong> In lieu of instantiating classes within the Google Maps environment, we propose the development of a distinct Polyline component. This approach would allow us to isolate and effectively manage any associated memory-related issues within this separate component.</li> -</ol> - -<h3 id="the-fix-for-google-maps-memory-leak">The fix for Google Maps memory leak</h3> - -<hr /> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2Ff108918c-c184-41f9-b6a7-2af7273ea800%2FUntitled.png?table=block&amp;id=80c8accc-556f-495f-813f-82e5ae28c497&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=2000&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>But we can try to Introduce a function to manually delete all of Google Map’s event listeners.</p> - -<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Helper function: Removes all event listeners registered with Google's addDomListener function,</span> -<span class="c1">// including from __e3_ properties on target objects.</span> -<span class="kd">function</span> <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">event</span><span class="p">)</span> <span class="p">{</span> - <span class="kd">var</span> <span class="nx">listeners</span> <span class="o">=</span> <span class="nx">target</span><span class="p">[</span><span class="dl">"</span><span class="s2">__e3_</span><span class="dl">"</span><span class="p">];</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">listeners</span><span class="p">)</span> <span class="p">{</span> - <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span> - <span class="dl">"</span><span class="s2">Couldn't find property __e3_ containing Google Maps listeners. Perhaps Google updated the Maps SDK?</span><span class="dl">"</span> - <span class="p">);</span> - <span class="k">return</span><span class="p">;</span> - <span class="p">}</span> - <span class="kd">var</span> <span class="nx">evListeners</span> <span class="o">=</span> <span class="nx">listeners</span><span class="p">[</span><span class="nx">event</span><span class="p">];</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">evListeners</span><span class="p">)</span> <span class="p">{</span> - <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">key</span> <span class="k">in</span> <span class="nx">evListeners</span><span class="p">)</span> <span class="p">{</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">evListeners</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="nx">key</span><span class="p">))</span> <span class="p">{</span> - <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">event</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="nx">evListeners</span><span class="p">[</span><span class="nx">key</span><span class="p">]);</span> - <span class="p">}</span> - <span class="p">}</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="c1">// Removes all DOM listeners for the given target and event.</span> -<span class="kd">function</span> <span class="nx">removeAllDOMListeners</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">event</span><span class="p">)</span> <span class="p">{</span> - <span class="kd">var</span> <span class="nx">listeners</span> <span class="o">=</span> <span class="nx">target</span><span class="p">[</span><span class="dl">"</span><span class="s2">__listeners_</span><span class="dl">"</span><span class="p">];</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">listeners</span> <span class="o">||</span> <span class="o">!</span><span class="nx">listeners</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span> - <span class="k">return</span><span class="p">;</span> - <span class="p">}</span> - - <span class="c1">// Copy to avoid iterating over array that we mutate via removeEventListener</span> - <span class="kd">var</span> <span class="nx">copy</span> <span class="o">=</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> - <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">copy</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> - <span class="nx">target</span><span class="p">.</span><span class="nx">removeEventListener</span><span class="p">(</span><span class="nx">event</span><span class="p">,</span> <span class="nx">copy</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="c1">// Shim addEventListener to capture and store registered event listeners.</span> -<span class="kd">var</span> <span class="nx">addEventListener</span> <span class="o">=</span> <span class="nx">EventTarget</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">;</span> -<span class="nx">EventTarget</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">addEventListener</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> - <span class="kd">var</span> <span class="nx">eventName</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> - <span class="kd">var</span> <span class="nx">listener</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">[</span><span class="dl">"</span><span class="s2">__listeners_</span><span class="dl">"</span><span class="p">])</span> <span class="p">{</span> - <span class="k">this</span><span class="p">.</span><span class="nx">__listeners_</span> <span class="o">=</span> <span class="p">{};</span> - <span class="p">}</span> - <span class="kd">var</span> <span class="nx">listeners</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">__listeners_</span><span class="p">;</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">listeners</span><span class="p">[</span><span class="nx">eventName</span><span class="p">])</span> <span class="p">{</span> - <span class="nx">listeners</span><span class="p">[</span><span class="nx">eventName</span><span class="p">]</span> <span class="o">=</span> <span class="p">[];</span> - <span class="p">}</span> - <span class="nx">listeners</span><span class="p">[</span><span class="nx">eventName</span><span class="p">].</span><span class="nx">push</span><span class="p">(</span><span class="nx">listener</span><span class="p">);</span> - <span class="k">return</span> <span class="nx">addEventListener</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span> -<span class="p">};</span> -<span class="kd">var</span> <span class="nx">removeEventListener</span> <span class="o">=</span> <span class="nx">EventTarget</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">removeEventListener</span><span class="p">;</span> -<span class="nx">EventTarget</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">removeEventListener</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span> - <span class="kd">var</span> <span class="nx">eventName</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> - <span class="kd">var</span> <span class="nx">listener</span> <span class="o">=</span> <span class="nx">arguments</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> - <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">[</span><span class="dl">"</span><span class="s2">__listeners_</span><span class="dl">"</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="k">this</span><span class="p">.</span><span class="nx">__listeners_</span><span class="p">[</span><span class="nx">eventName</span><span class="p">])</span> <span class="p">{</span> - <span class="c1">// Loop because the same listener may be added twice with different</span> - <span class="c1">// options, and because our simple addEventListener shim doesn't</span> - <span class="c1">// check for duplicates.</span> - <span class="k">while</span> <span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span> - <span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">__listeners_</span><span class="p">[</span><span class="nx">eventName</span><span class="p">].</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">listener</span><span class="p">);</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">===</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> - <span class="k">break</span><span class="p">;</span> - <span class="p">}</span> - <span class="k">this</span><span class="p">.</span><span class="nx">__listeners_</span><span class="p">[</span><span class="nx">eventName</span><span class="p">].</span><span class="nx">splice</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> - <span class="p">}</span> - <span class="p">}</span> - <span class="k">return</span> <span class="nx">removeEventListener</span><span class="p">.</span><span class="nx">apply</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="nx">arguments</span><span class="p">);</span> -<span class="p">};</span> - -<span class="c1">// After you remove the Google Map from the DOM, call this function to completely free the object.</span> -<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">destroyGoogleMaps</span><span class="p">(</span><span class="nb">window</span><span class="p">)</span> <span class="p">{</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="dl">"</span><span class="s2">blur</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="dl">"</span><span class="s2">resize</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">keydown</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">keypress</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">keyup</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">MSFullscreenChange</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">fullscreenchange</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">mozfullscreenchange</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllGoogleListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="dl">"</span><span class="s2">webkitfullscreenchange</span><span class="dl">"</span><span class="p">);</span> - <span class="c1">// ASSUMPTION: No other library registers global resize and scroll event listeners! If this is not true, then you'll need to add logic to avoid removing these.</span> - <span class="nx">removeAllDOMListeners</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="dl">"</span><span class="s2">resize</span><span class="dl">"</span><span class="p">);</span> - <span class="nx">removeAllDOMListeners</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="dl">"</span><span class="s2">scroll</span><span class="dl">"</span><span class="p">);</span> -<span class="p">}</span> -</code></pre></div></div> - -<p>Credit to this commenter: <a href="https://issuetracker.google.com/issues/35821412#comment53">https://issuetracker.google.com/issues/35821412#comment53</a></p> - -<p>This resolves the memory issue to an extent.</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2Ffe42a452-2cc2-427c-968f-82db2d143156%2FUntitled.png?table=block&amp;id=0d8af477-8bce-4572-aab4-45dd1c0d31e0&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=1150&amp;userId=&amp;cache=v2" alt="The flow observed is. Landing page → Page with Trips View → Page with another Google Map → Page without Google Map" /></p> - -<p>The flow observed is. Landing page → Page with Trips View → Page with another Google Map → Page without Google Map</p> - -<p>In Prod and Staging, the Page without Google Maps hogs up memory while introducing the memory cleanup in dev shows us that it requires way less memory!</p> - -<h3 id="the-fix-for-three-drawings">The fix for three drawings</h3> - -<hr /> - -<p>This one happens to be very simple. While creating a <code class="language-plaintext highlighter-rouge">Polyline</code>, just specify an icon and set the <code class="language-plaintext highlighter-rouge">repeat</code> value as <code class="language-plaintext highlighter-rouge">100%</code>.</p> - -<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">new</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">Polyline</span><span class="p">({</span> - <span class="na">strokeColor</span><span class="p">:</span> <span class="nx">props</span><span class="p">.</span><span class="nx">color</span><span class="p">,</span> - <span class="na">geodesic</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> - <span class="na">strokeWeight</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> - <span class="na">icons</span><span class="p">:</span> <span class="p">[</span> - <span class="p">{</span> - <span class="na">icon</span><span class="p">:</span> <span class="p">{</span> - <span class="na">path</span><span class="p">:</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">SymbolPath</span><span class="p">.</span><span class="nx">CIRCLE</span><span class="p">,</span> - <span class="p">},</span> - <span class="na">repeat</span><span class="p">:</span> <span class="dl">"</span><span class="s2">100%</span><span class="dl">"</span><span class="p">,</span> - <span class="p">},</span> - <span class="p">],</span> -<span class="p">});</span> -</code></pre></div></div> - -<p>We can even make the <code class="language-plaintext highlighter-rouge">icon</code> a <code class="language-plaintext highlighter-rouge">SymbolPath.FORWARD_PATH</code> (Reference: <a href="https://developers.google.com/maps/documentation/javascript/reference/marker#SymbolPath">https://developers.google.com/maps/documentation/javascript/reference/marker#SymbolPath</a>) indicating the trip direction as well!</p> - -<h3 id="making-the-polylines-an-overlay">Making the Polylines an Overlay</h3> - -<hr /> - -<p>Now all of the computations happen inside the <code class="language-plaintext highlighter-rouge">onGoogleApiLoaded</code> method of <code class="language-plaintext highlighter-rouge">google-map-react</code>.</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2Fc21921e8-55ab-43f5-988b-7b687e7d6640%2FUntitled.png?table=block&amp;id=adc3f881-36c7-434c-8519-eefa45454bcc&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=2000&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>First thing, we make this function do nothing but set a state called <code class="language-plaintext highlighter-rouge">map</code>. This is for us to later set the <code class="language-plaintext highlighter-rouge">PolyLine</code> on to the map.</p> - -<p><code class="language-plaintext highlighter-rouge">Polyline.js</code></p> - -<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> - -<span class="k">import</span> <span class="nx">useDeepCompareEffect</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">use-deep-compare-effect</span><span class="dl">"</span><span class="p">;</span> - -<span class="kd">function</span> <span class="nx">pathsDiffer</span><span class="p">(</span><span class="nx">path1</span><span class="p">,</span> <span class="nx">path2</span><span class="p">)</span> <span class="p">{</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">path1</span><span class="p">.</span><span class="nx">getLength</span><span class="p">()</span> <span class="o">!=</span> <span class="nx">path2</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span> - <span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="p">[</span><span class="nx">i</span><span class="p">,</span> <span class="nx">val</span><span class="p">]</span> <span class="k">of</span> <span class="nx">path2</span><span class="p">.</span><span class="nx">entries</span><span class="p">())</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">path1</span><span class="p">.</span><span class="nx">getAt</span><span class="p">(</span><span class="nx">i</span><span class="p">).</span><span class="nx">toJSON</span><span class="p">()</span> <span class="o">!=</span> <span class="nx">val</span><span class="p">)</span> <span class="k">return</span> <span class="kc">true</span><span class="p">;</span> - <span class="k">return</span> <span class="kc">false</span><span class="p">;</span> -<span class="p">}</span> - -<span class="k">export</span> <span class="k">default</span> <span class="kd">function</span> <span class="nx">PolyLine</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span> - <span class="kd">const</span> <span class="p">[</span><span class="nx">polyline</span><span class="p">,</span> <span class="nx">setPolyline</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span> - - <span class="nx">useDeepCompareEffect</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> - <span class="c1">// Create polyline after map initialized.</span> - <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">polyline</span> <span class="o">&amp;&amp;</span> <span class="nx">props</span><span class="p">.</span><span class="nx">map</span><span class="p">)</span> <span class="p">{</span> - <span class="nx">setPolyline</span><span class="p">(</span> - <span class="k">new</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">Polyline</span><span class="p">({</span> - <span class="na">strokeColor</span><span class="p">:</span> <span class="nx">props</span><span class="p">.</span><span class="nx">color</span><span class="p">,</span> - <span class="na">geodesic</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> - <span class="na">strokeWeight</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> - <span class="na">icons</span><span class="p">:</span> <span class="p">[</span> - <span class="p">{</span> - <span class="na">icon</span><span class="p">:</span> <span class="p">{</span> - <span class="na">path</span><span class="p">:</span> <span class="nx">google</span><span class="p">.</span><span class="nx">maps</span><span class="p">.</span><span class="nx">SymbolPath</span><span class="p">.</span><span class="nx">FORWARD_CLOSED_ARROW</span><span class="p">,</span> - <span class="p">},</span> - <span class="na">repeat</span><span class="p">:</span> <span class="dl">"</span><span class="s2">100%</span><span class="dl">"</span><span class="p">,</span> - <span class="p">},</span> - <span class="p">],</span> - <span class="p">})</span> - <span class="p">);</span> - <span class="p">}</span> - - <span class="c1">// Synchronize map polyline with component props.</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">polyline</span> <span class="o">&amp;&amp;</span> <span class="nx">polyline</span><span class="p">.</span><span class="nx">getMap</span><span class="p">()</span> <span class="o">!=</span> <span class="nx">props</span><span class="p">.</span><span class="nx">map</span><span class="p">)</span> <span class="nx">polyline</span><span class="p">.</span><span class="nx">setMap</span><span class="p">(</span><span class="nx">props</span><span class="p">.</span><span class="nx">map</span><span class="p">);</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">polyline</span> <span class="o">&amp;&amp;</span> <span class="nx">pathsDiffer</span><span class="p">(</span><span class="nx">polyline</span><span class="p">.</span><span class="nx">getPath</span><span class="p">(),</span> <span class="nx">props</span><span class="p">.</span><span class="nx">path</span><span class="p">))</span> - <span class="nx">polyline</span><span class="p">.</span><span class="nx">setPath</span><span class="p">(</span><span class="nx">props</span><span class="p">.</span><span class="nx">path</span><span class="p">);</span> - - <span class="k">return</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> - <span class="c1">// Cleanup: remove line from map</span> - <span class="k">if</span> <span class="p">(</span><span class="nx">polyline</span><span class="p">)</span> <span class="nx">polyline</span><span class="p">.</span><span class="nx">setMap</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span> - <span class="p">};</span> - <span class="p">},</span> <span class="p">[</span><span class="nx">props</span><span class="p">,</span> <span class="nx">polyline</span><span class="p">]);</span> - - <span class="k">return</span> <span class="kc">null</span><span class="p">;</span> -<span class="p">}</span> -</code></pre></div></div> - -<p>Now inside the component,</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2F06f2f061-7282-4b42-b7bf-05a516c6948a%2FUntitled.png?table=block&amp;id=fb0f015d-24d0-4dda-b856-b0f1071b8920&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=2000&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>Finally, as a sibling to <code class="language-plaintext highlighter-rouge">GoogleMapReact</code> we introduce the <code class="language-plaintext highlighter-rouge">Polyline</code> component.</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2F1b6f3ecc-80c9-4b1e-8d59-243dc478a655%2FUntitled.png?table=block&amp;id=fd6242dd-8dd0-4275-9be4-3c536257d5e6&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=770&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<h3 id="final-result">Final Result</h3> - -<hr /> - -<p>Maps look way more meaningful</p> - -<p><img src="https://thisdot.notion.site/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2Feb53edbf-045d-426c-aa09-d626c2816f18%2F31bb1d16-a928-4993-940d-dba7f906cfe8%2FUntitled.png?table=block&amp;id=2614941e-393c-448d-b6cc-87fa477d10e6&amp;spaceId=eb53edbf-045d-426c-aa09-d626c2816f18&amp;width=2000&amp;userId=&amp;cache=v2" alt="Untitled" /></p> - -<p>The memory consumption which went from <code class="language-plaintext highlighter-rouge">500MB</code> to <code class="language-plaintext highlighter-rouge">367MB</code> after memory cleanup, went down to <code class="language-plaintext highlighter-rouge">140MB</code> after removing the marker drawings!</p>Rahul KrishnaPremise \ No newline at end of file +<p>Julia Evans’ Blog Article: <a href="https://jvns.ca/blog/2023/10/20/some-miscellaneous-git-facts/">https://jvns.ca/blog/2023/10/20/some-miscellaneous-git-facts/</a></p>Rahul KrishnaWhat is a Stash? \ No newline at end of file diff --git a/_site/index.html b/_site/index.html index 14ae15f..acb7c18 100644 --- a/_site/index.html +++ b/_site/index.html @@ -97,6 +97,18 @@

Fie
  • +
    + + Recursion in React +  -  + Feb 21, 2024 +
    + + +
  • + + +
  • Arc Search diff --git a/_site/notes/2024/02/10/arc-search.html b/_site/notes/2024/02/10/arc-search.html index 8dd4371..7edcd3d 100644 --- a/_site/notes/2024/02/10/arc-search.html +++ b/_site/notes/2024/02/10/arc-search.html @@ -115,7 +115,7 @@

    What is it?

    Here is what Arc Search has to say about Arc Search!

    -
    +

    Basic Stuff it does

    @@ -226,6 +226,14 @@

    References

    + + diff --git a/images/budgeting-tool/.DS_Store b/images/budgeting-tool/.DS_Store deleted file mode 100644 index a8c3398c2822a5128d46c5eb133edba311962877..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 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 d$|pvI*P__U7 literal 0 HcmV?d00001 diff --git a/images/recursion-in-react/react-result.png b/images/recursion-in-react/react-result.png new file mode 100644 index 0000000000000000000000000000000000000000..671f5c42c2e6becbc41bf2420f4c9d2efb08278d GIT binary patch literal 7360 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 W>E5c_QvdVON=Z&#wp!*@$o~K+>x-rU literal 0 HcmV?d00001 diff --git a/images/recursion-in-react/real-life-example.png b/images/recursion-in-react/real-life-example.png new file mode 100644 index 0000000000000000000000000000000000000000..250aee748b2386110a6da1b466055396e1a0c4d4 GIT binary patch literal 67604 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 G-u*9r4ULol literal 0 HcmV?d00001