DEV Community: Meat BoyThe latest articles on DEV Community by Meat Boy (@meatboy).
https://dev.to/meatboy
https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267194%2F3db4562b-8873-4e13-be10-eee8e200422d.jpgDEV Community: Meat Boy
https://dev.to/meatboy
enHow to add Limited Login Facebook on iOS and Android on server-side and client-sideMeat BoyMon, 19 Aug 2024 19:54:57 +0000
https://dev.to/meatboy/how-to-add-limited-login-facebook-on-ios-and-android-on-server-side-and-client-side-4616
https://dev.to/meatboy/how-to-add-limited-login-facebook-on-ios-and-android-on-server-side-and-client-side-4616<p>Meta recently introduced the concept of Limited Login for iOS authentication with Facebook. This tutorial provides a step-by-step guide on integrating Facebook Login into a React Native application, including server-side implementation, with a focus on supporting both standard and limited login flows in 2024.</p>
<h1>
1. Project Initialisation
</h1>
<p>If you have an existing application, you may bypass this section. For those starting anew, follow these instructions to create a new application:<br>
<a href="proxy.php?url=https://reactnative.dev/docs/getting-started-without-a-framework" rel="noopener noreferrer">Initialise a new project using Expo</a><br>
<a href="proxy.php?url=https://reactnative.dev/docs/environment-setup" rel="noopener noreferrer">Initialise a new project with React Native CLI</a></p>
<h1>
2. Installation of react-native-fbsdk-next
</h1>
<p>Follow the official documentation for installation instructions:<br>
<a href="proxy.php?url=https://github.com/thebergamo/react-native-fbsdk-next/#expo-installation" rel="noopener noreferrer">FBSDK Next - Expo Setup</a><br>
or<br>
<a href="proxy.php?url=https://github.com/thebergamo/react-native-fbsdk-next/?tab=readme-ov-file#1-install-the-library" rel="noopener noreferrer">FBSDK Next - React Native CLI Setup</a></p>
<h1>
3. Implementation of Limited Login on the Client Side
</h1>
<p>Integrate the following code snippet to implement Limited Login in your React Native project:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="kd">const</span> <span class="nx">loginWithFacebook</span> <span class="o">=</span> <span class="k">async </span><span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">LoginManager</span><span class="p">.</span><span class="nf">logInWithPermissions</span><span class="p">(</span>
<span class="p">[</span><span class="dl">'</span><span class="s1">public_profile</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">email</span><span class="dl">'</span><span class="p">],</span>
<span class="dl">'</span><span class="s1">limited</span><span class="dl">'</span> <span class="c1">// This parameter ensures consistent limited login behaviour on iOS</span>
<span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">isCancelled</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">let</span> <span class="nx">token</span> <span class="o">=</span> <span class="k">await </span><span class="p">(</span><span class="nx">Platform</span><span class="p">.</span><span class="nx">OS</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">ios</span><span class="dl">'</span>
<span class="p">?</span> <span class="nx">AuthenticationToken</span><span class="p">.</span><span class="nf">getAuthenticationTokenIOS</span><span class="p">().</span><span class="nf">then</span><span class="p">(</span>
<span class="nx">data</span> <span class="o">=></span> <span class="nx">data</span><span class="p">?.</span><span class="nx">authenticationToken</span> <span class="o">||</span> <span class="dl">''</span>
<span class="p">)</span>
<span class="p">:</span> <span class="nx">AccessToken</span><span class="p">.</span><span class="nf">getCurrentAccessToken</span><span class="p">().</span><span class="nf">then</span><span class="p">(</span>
<span class="nx">data</span> <span class="o">=></span> <span class="nx">data</span><span class="p">?.</span><span class="nx">accessToken</span> <span class="o">||</span> <span class="dl">''</span>
<span class="p">));</span>
<span class="c1">// Utilise the token for further operations, such as server-side authentication</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
</code></pre>
</div>
<h1>
4. Server-Side Token Validation
</h1>
<p>The server-side implementation requires handling both authorisation codes and authentication codes to support standard and limited login flows.</p>
<p>Let's create a new endpoint using <code>express</code>. Note that this approach can be adapted to other web server frameworks with minimal modifications.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="nx">router</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/auth/facebook</span><span class="dl">'</span><span class="p">,</span> <span class="k">async </span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">facebookToken</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">;</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">facebookUserId</span><span class="p">,</span> <span class="nx">facebookUserName</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">getFacebookUser</span><span class="p">({</span> <span class="na">token</span><span class="p">:</span> <span class="nx">facebookToken</span><span class="p">,</span> <span class="na">appId</span><span class="p">:</span> <span class="nx">facebookAppId</span> <span class="p">});</span>
<span class="c1">// Utilise facebookUserId and facebookUserName for user creation or authentication</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Token exchange or validation failure; handle the error or pass it to the next middleware</span>
<span class="nf">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre>
</div>
<p>Now, let's implement the <code>getFacebookUser</code> function to validate and exchange tokens for user data. This function handles both authentication tokens and OIDC Authorisation Tokens.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="kr">interface</span> <span class="nx">FacebookUser</span> <span class="p">{</span>
<span class="nl">facebookUserId</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">facebookUserName</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="kr">interface</span> <span class="nx">GetFacebookUserParams</span> <span class="p">{</span>
<span class="nl">token</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">appId</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">getFacebookUser</span><span class="p">({</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">appId</span> <span class="p">}:</span> <span class="nx">GetFacebookUserParams</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="nx">FacebookUser</span><span class="o">></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">await</span> <span class="nf">getStandardFacebookUser</span><span class="p">(</span><span class="nx">token</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="dl">'</span><span class="s1">Failed to get standard Facebook user, trying limited user</span><span class="dl">'</span><span class="p">);</span>
<span class="k">return</span> <span class="nf">getLimitedFacebookUser</span><span class="p">({</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">appId</span> <span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>First, let's handle the standard flow Authorisation Code. You can simply use it to exchange data by calling API. We will use <code>axios</code> for REST API calls. You may also need <code>jwks-rsa</code> for extracting the proper key from jwks endpoint (you may also use axios, but it requires a little more effort) and <code>jsonwebtoken</code> library for validation and decoding of JWT. Of course, you can use any other tech stack. The general idea will be the same in Go, Python or Java.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="kd">const</span> <span class="nx">FACEBOOK_GRAPH_API</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://graph.facebook.com/me</span><span class="dl">'</span><span class="p">;</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nf">getStandardFacebookUser</span><span class="p">(</span><span class="nx">token</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="nx">FacebookUser</span><span class="o">></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">axios</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">FACEBOOK_GRAPH_API</span><span class="p">}</span><span class="s2">?fields=id,name&access_token=</span><span class="p">${</span><span class="nx">token</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">data</span><span class="p">.</span><span class="nx">id</span> <span class="o">||</span> <span class="o">!</span><span class="nx">data</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Invalid token (missing id or name)</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">facebookUserId</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="na">facebookUserName</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">name</span> <span class="p">};</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">axios</span><span class="p">.</span><span class="nf">isAxiosError</span><span class="p">(</span><span class="nx">error</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`Failed to fetch Facebook user: </span><span class="p">${</span><span class="nx">error</span><span class="p">.</span><span class="nx">message</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">throw</span> <span class="nx">error</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>In the response, you will get both the id and the name of the user scoped into your application. If any data is missing, we will throw an error. No matter what the issue is, we still want to give the user a chance to sign in. Maybe the user signed in using iOS with ATT turned off and the token is OIDC Authentication Token. Then we need to:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="kd">const</span> <span class="nx">FACEBOOK_JWKS_URI</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://www.facebook.com/.well-known/oauth/openid/jwks</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">FACEBOOK_ISSUER</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://www.facebook.com</span><span class="dl">'</span><span class="p">;</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nf">getLimitedFacebookUser</span><span class="p">({</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">appId</span> <span class="p">}:</span> <span class="nx">GetFacebookUserParams</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="nx">FacebookUser</span><span class="o">></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">client</span> <span class="o">=</span> <span class="nf">jwksClient</span><span class="p">({</span> <span class="na">jwksUri</span><span class="p">:</span> <span class="nx">FACEBOOK_JWKS_URI</span> <span class="p">});</span>
<span class="k">return</span> <span class="k">new</span> <span class="nc">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">jwt</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span>
<span class="nx">token</span><span class="p">,</span>
<span class="k">async </span><span class="p">(</span><span class="nx">header</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">client</span><span class="p">.</span><span class="nf">getSigningKey</span><span class="p">(</span><span class="nx">header</span><span class="p">.</span><span class="nx">kid</span><span class="p">);</span>
<span class="nf">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">key</span><span class="p">.</span><span class="nf">getPublicKey</span><span class="p">());</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">callback</span><span class="p">(</span><span class="nx">error</span> <span class="k">as</span> <span class="nb">Error</span><span class="p">,</span> <span class="kc">undefined</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="na">algorithms</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">RS256</span><span class="dl">'</span><span class="p">],</span>
<span class="na">audience</span><span class="p">:</span> <span class="nx">appId</span><span class="p">,</span>
<span class="na">issuer</span><span class="p">:</span> <span class="nx">FACEBOOK_ISSUER</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">decoded</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">reject</span><span class="p">(</span><span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="s2">`JWT verification failed: </span><span class="p">${</span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="p">}</span><span class="s2">`</span><span class="p">));</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">sub</span><span class="p">,</span> <span class="nx">name</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">decoded</span> <span class="k">as</span> <span class="nx">JwtPayload</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">sub</span> <span class="o">||</span> <span class="o">!</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">reject</span><span class="p">(</span><span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Invalid token (missing sub or name)</span><span class="dl">'</span><span class="p">));</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">resolve</span><span class="p">({</span> <span class="na">facebookUserId</span><span class="p">:</span> <span class="nx">sub</span><span class="p">,</span> <span class="na">facebookUserName</span><span class="p">:</span> <span class="nx">name</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="p">}</span>
</code></pre>
</div>
<p>In the code above, first, you create a new <code>JWKS</code> client looking for a list of public keys of Facebook. Then you will extract key <code>id</code> (kid) from JWT to get the proper public key. At this moment, all JWT signatures are signed using <code>RS256</code> algorithm, so you have to specify that. The audience of the JWT is your application, so it must be set to appId from the Facebook app developer dashboard. The issuer is constant and always <code>https://www.facebook.com</code>.</p>
<p>In the next step, JWT will be either validated or not. If it's validated, you can safely decode it and get both sub and name. The <code>sub</code> property is the user id in your Facebook application scope, while <code>name</code> is the public display name of the user.</p>
<p>The whole code looks like this:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="k">import</span> <span class="nx">jwksLocalClient</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">jwks-rsa</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">jwt</span><span class="p">,</span> <span class="p">{</span> <span class="nx">JwtPayload</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">jsonwebtoken</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">axios</span><span class="p">,</span> <span class="p">{</span> <span class="nx">isAxiosError</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">axios</span><span class="dl">'</span><span class="p">;</span>
<span class="k">export</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">getStandardFacebookUser</span><span class="p">(</span><span class="nx">token</span><span class="p">:</span> <span class="kr">string</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">data</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">axios</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="s2">`https://graph.facebook.com/me?fields=id,name&access_token=</span><span class="p">${</span><span class="nx">token</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">data</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Invalid token (missing id or name)</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">facebookUserId</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span> <span class="na">facebookUserName</span><span class="p">:</span> <span class="nx">data</span><span class="p">.</span><span class="nx">name</span> <span class="p">};</span>
<span class="p">}</span>
<span class="k">export</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">getLimitedFacebookUser</span><span class="p">({</span>
<span class="nx">token</span><span class="p">,</span>
<span class="nx">appId</span><span class="p">,</span>
<span class="p">}:</span> <span class="p">{</span>
<span class="nl">token</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">appId</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">})</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">jwksClient</span> <span class="o">=</span> <span class="nf">jwksLocalClient</span><span class="p">({</span>
<span class="na">jwksUri</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://www.facebook.com/.well-known/oauth/openid/jwks</span><span class="dl">'</span><span class="p">,</span>
<span class="p">});</span>
<span class="k">return</span> <span class="k">new</span> <span class="nb">Promise</span><span class="o"><</span><span class="p">{</span>
<span class="na">facebookUserId</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">facebookUserName</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">}</span><span class="o">></span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">jwt</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span>
<span class="nx">token</span><span class="p">,</span>
<span class="k">async </span><span class="p">(</span><span class="nx">header</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">key</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">jwksClient</span><span class="p">.</span><span class="nf">getSigningKey</span><span class="p">(</span><span class="nx">header</span><span class="p">.</span><span class="nx">kid</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">signingKey</span> <span class="o">=</span> <span class="nx">key</span><span class="p">.</span><span class="nf">getPublicKey</span><span class="p">();</span>
<span class="nf">callback</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span> <span class="nx">signingKey</span><span class="p">);</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="na">algorithms</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">RS256</span><span class="dl">'</span><span class="p">],</span>
<span class="na">audience</span><span class="p">:</span> <span class="nx">appId</span><span class="p">,</span>
<span class="na">issuer</span><span class="p">:</span> <span class="dl">'</span><span class="s1">https://www.facebook.com</span><span class="dl">'</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">decoded</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="nf">reject</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">decodedData</span> <span class="o">=</span> <span class="nx">decoded</span> <span class="k">as</span> <span class="nx">JwtPayload</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">decodedData</span><span class="p">.</span><span class="nx">sub</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">reject</span><span class="p">(</span><span class="k">new</span> <span class="nc">Error</span><span class="p">(</span><span class="dl">'</span><span class="s1">Invalid token (missing sub)</span><span class="dl">'</span><span class="p">));</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nf">resolve</span><span class="p">({</span> <span class="na">facebookUserId</span><span class="p">:</span> <span class="nx">decodedData</span><span class="p">.</span><span class="nx">sub</span><span class="p">,</span> <span class="na">facebookUserName</span><span class="p">:</span> <span class="nx">decodedData</span><span class="p">.</span><span class="nx">name</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="k">export</span> <span class="k">async</span> <span class="kd">function</span> <span class="nf">getFacebookUser</span><span class="p">({</span>
<span class="nx">token</span><span class="p">,</span>
<span class="nx">appId</span><span class="p">,</span>
<span class="p">}:</span> <span class="p">{</span>
<span class="nl">token</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="nl">appId</span><span class="p">:</span> <span class="kr">string</span><span class="p">;</span>
<span class="p">})</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">await</span> <span class="nf">getStandardFacebookUser</span><span class="p">(</span><span class="nx">token</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if </span><span class="p">(</span><span class="nf">isAxiosError</span><span class="p">(</span><span class="nx">error</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nf">warn</span><span class="p">(</span><span class="dl">'</span><span class="s1">Failed to get standard Facebook user, trying limited user</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nf">getLimitedFacebookUser</span><span class="p">({</span>
<span class="nx">token</span><span class="p">,</span>
<span class="nx">appId</span><span class="p">,</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">router</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/auth/facebook</span><span class="dl">'</span><span class="p">,</span> <span class="k">async </span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">facebookToken</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">;</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">facebookUserId</span><span class="p">,</span> <span class="nx">facebookUserName</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">getFacebookUser</span><span class="p">({</span> <span class="na">token</span><span class="p">:</span> <span class="nx">facebookToken</span><span class="p">,</span> <span class="na">appId</span><span class="p">:</span> <span class="nx">facebookAppId</span> <span class="p">});</span>
<span class="c1">// Utilise facebookUserId and facebookUserName for user creation or authentication</span>
<span class="p">}</span> <span class="k">catch </span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Token exchange or validation failure; handle the error or pass it to the next middleware</span>
<span class="nf">next</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre>
</div>
<p>This implementation provides a quick solution for authenticating users regardless of their chosen login flow. If you require further assistance, please leave a comment, and I will do my best to help :)</p>
reactnativereacttutorialtypescriptHow I created AI-powered ORM for PostgreSQL, MySQL and SQLite and why you shouldn't use itMeat BoyFri, 13 Oct 2023 10:54:19 +0000
https://dev.to/meatboy/how-i-created-ai-powered-orm-for-postgresql-mysql-and-sqlite-and-why-you-shouldnt-use-it-1a
https://dev.to/meatboy/how-i-created-ai-powered-orm-for-postgresql-mysql-and-sqlite-and-why-you-shouldnt-use-it-1a<blockquote>
<p>tl;dr<br>
I created AI-powered ORM for Node with TypeScript or JavaScript called <a href="proxy.php?url=https://www.npmjs.com/package/ormgpt" rel="noopener noreferrer">ormgpt</a>. It works, it's silly and please don't use it.</p>
<pre class="highlight shell"><code>npm <span class="nb">install </span>ormgpt
</code></pre>
</blockquote>
<h3>
Cutting edge, blazing fast technology everywhere
</h3>
<p>In the last few years number of new ORMs (object relation mappers) and query builders has grown like crazy. A few years ago, the golden standard was either an ORM like Sequelize or a query builder like Knex. Since then we got TypeORM, Bookshelf, Objection, Mikro-ORM, Prisma, Drizzle, kysely and many, many more. While I agree that more option is good since anyone can choose the best-suited solution for their needs, it also creates many copy-alike libs.</p>
<p>At this point, I think ORMs have become the new days since the last javascript frameworks but for the backend.</p>
<p>Another hot topic, wider than just the javascript ecosystem is AI. Entire group of algorithms to recognize patterns, predict output and generate things. Now tech startup not only must store data in the hot blockchain, NoSQL or vector database, but compute on edge computing using quantum technology. Must be also AI - artificially intelligent. </p>
<p><a href="proxy.php?url=https://i.giphy.com/media/ckJF143W1gBS8Hk833/giphy.gif" class="article-body-image-wrapper"><img src="proxy.php?url=https://i.giphy.com/media/ckJF143W1gBS8Hk833/giphy.gif" alt="AI"></a></p>
<h3>
Afternoon idea
</h3>
<p>My thought was, what if I create a hot, new lib to access data like ORMs or query builders but using AI? So anyone can access data using plain language like:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight shell"><code>give me 10 recent posts from the category travel and where the author is John Doe, with the author and comments info
</code></pre>
</div>
<p>or even in other languages like for example German<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight shell"><code>bitte legen Sie einen neuen Benutzer Hans Schmidt mit Wohnadresse München, Kaufingerstraße und Neuhauser Straße 1A an
</code></pre>
</div>
<p>so I messed a little with OpenAI API to call with prompts like<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="nx">Prepare</span> <span class="nx">SQL</span> <span class="nx">query</span> <span class="k">for</span> <span class="nx">$</span><span class="p">{</span><span class="nx">prompt</span><span class="p">}</span>
</code></pre>
</div>
<p>but that was too general. I tried then<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="nx">Having</span> <span class="nx">database</span> <span class="nx">schema</span><span class="p">:</span>
<span class="nx">$</span><span class="p">{</span><span class="nx">dbSchema</span><span class="p">}</span>
<span class="nx">Prepare</span> <span class="nx">SQL</span> <span class="nx">query</span> <span class="k">for</span><span class="p">:</span>
<span class="nx">$</span><span class="p">{</span><span class="nx">prompt</span><span class="p">}</span>
</code></pre>
</div>
<p>still, often it was returning with invalid queries or additional comments. So I went even stricter passing also dialect, entire db schema and asking to not write any other response than a query.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="nx">You</span> <span class="nx">are</span> <span class="nx">an</span> <span class="nx">SQL</span> <span class="nx">engine</span> <span class="nx">brain</span><span class="p">.</span>
<span class="nx">You</span> <span class="nx">are</span> <span class="nx">using</span> <span class="nx">$</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">dialect</span><span class="p">}</span> <span class="nx">dialect</span><span class="p">.</span>
<span class="nx">Having</span> <span class="nx">db</span> <span class="nx">schema</span> <span class="k">as</span> <span class="nx">follows</span><span class="p">:</span>
<span class="nx">$</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">dbSchema</span><span class="p">}</span>
<span class="nx">Write</span> <span class="nx">a</span> <span class="nx">query</span> <span class="nx">to</span> <span class="nx">fulfil</span> <span class="nx">the</span> <span class="nx">user</span> <span class="nx">request</span><span class="p">:</span> <span class="nx">$</span><span class="p">{</span><span class="nx">request</span><span class="p">}</span>
<span class="nx">Don</span><span class="dl">'</span><span class="s1">t write anything else than SQL query.
</span></code></pre>
</div>
<p>And that worked quite well. So the next part was to prepare methods to call OpenAI programmatically and adapters for database engines. </p>
<p>Method calling OpenAI was pretty simple and using built-in fetch:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code>
<span class="k">private</span> <span class="k">async</span> <span class="nf">getResponse</span><span class="p">(</span><span class="nx">request</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="kr">string</span><span class="o">></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">prompt</span> <span class="o">=</span> <span class="s2">`
You are an SQL engine brain.
You are using </span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">dialect</span><span class="p">}</span><span class="s2"> dialect.
Having db schema as follows:
</span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">dbSchema</span><span class="p">}</span><span class="s2">
Write a query to fulfil the user request: </span><span class="p">${</span><span class="nx">request</span><span class="p">}</span><span class="s2">
Don't write anything else than SQL query.
`</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">response</span> <span class="o">=</span> <span class="k">await</span> <span class="nf">fetch</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">apiUrl</span><span class="p">,</span> <span class="p">{</span>
<span class="na">method</span><span class="p">:</span> <span class="dl">"</span><span class="s2">POST</span><span class="dl">"</span><span class="p">,</span>
<span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">,</span>
<span class="na">Authorization</span><span class="p">:</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="k">this</span><span class="p">.</span><span class="nx">apiKey</span><span class="p">}</span><span class="s2">`</span><span class="p">,</span>
<span class="p">},</span>
<span class="na">body</span><span class="p">:</span> <span class="nx">JSON</span><span class="p">.</span><span class="nf">stringify</span><span class="p">({</span>
<span class="na">model</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">,</span>
<span class="na">messages</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="na">role</span><span class="p">:</span> <span class="dl">"</span><span class="s2">user</span><span class="dl">"</span><span class="p">,</span>
<span class="na">content</span><span class="p">:</span> <span class="nx">prompt</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">],</span>
<span class="p">...</span><span class="k">this</span><span class="p">.</span><span class="nx">modelOptions</span><span class="p">,</span>
<span class="p">}),</span>
<span class="p">});</span>
<span class="kd">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="p">(</span><span class="k">await</span> <span class="nx">response</span><span class="p">.</span><span class="nf">json</span><span class="p">())</span> <span class="k">as</span> <span class="nx">ErrorResponse</span> <span class="o">|</span> <span class="nx">SuccessResponse</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nf">hasOwnProperty</span><span class="p">(</span><span class="dl">"</span><span class="s2">error</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nc">Error</span><span class="p">((</span><span class="nx">data</span> <span class="k">as</span> <span class="nx">ErrorResponse</span><span class="p">).</span><span class="nx">error</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return </span><span class="p">(</span><span class="nx">data</span> <span class="k">as</span> <span class="nx">SuccessResponse</span><span class="p">).</span><span class="nx">choices</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">message</span><span class="p">.</span><span class="nx">content</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<p>I know OpenAI has also SDK lib but I prefer simple calls instead of another dependency since it's hard to manage them in the long term. API allows direct access to the resource, SDK package would have to be updated separately and eventually can be abandoned.</p>
<p><a href="proxy.php?url=https://i.giphy.com/media/1g2JyW7p6mtZc6bOEY/giphy.gif" class="article-body-image-wrapper"><img src="proxy.php?url=https://i.giphy.com/media/1g2JyW7p6mtZc6bOEY/giphy.gif" alt="pkg"></a></p>
<p>For the database engine, I choose to support Postgres, MySQL and SQLite out of the box. They are the most popular and I worked with all of them before with success. The first was SQLite which allowed me to experiment with different interfaces of adapter. With such an interface, anyone can create their own adapter for other engines like Oracle, ClickHouse, CouchDB etc. I decided to stick with the smallest possible set of methods in the interface, leaving other responsibilities than executing queries to native clients:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="k">export</span> <span class="kr">interface</span> <span class="nx">DatabaseEngineAdapter</span> <span class="p">{</span>
<span class="nf">executeQuery</span><span class="p">(</span><span class="nx">query</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="kr">any</span><span class="p">[]</span><span class="o">></span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<p>Then I created silly adapters:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="k">import</span> <span class="p">{</span> <span class="nx">DatabaseEngineAdapter</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./DatabaseEngineAdapter</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">betterSqlite3</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Statement</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">better-sqlite3</span><span class="dl">"</span><span class="p">;</span>
<span class="k">export</span> <span class="kd">class</span> <span class="nc">SqliteAdapter</span> <span class="k">implements</span> <span class="nx">DatabaseEngineAdapter</span> <span class="p">{</span>
<span class="k">private</span> <span class="nx">db</span><span class="p">:</span> <span class="nx">betterSqlite3</span><span class="p">.</span><span class="nx">Database</span><span class="p">;</span>
<span class="nf">constructor</span><span class="p">({</span> <span class="nx">dbFilePath</span> <span class="p">}:</span> <span class="p">{</span> <span class="nl">dbFilePath</span><span class="p">:</span> <span class="kr">string</span> <span class="p">})</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">db</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">betterSqlite3</span><span class="p">(</span><span class="nx">dbFilePath</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">executeQuery</span><span class="p">(</span><span class="nx">query</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nb">Promise</span><span class="o"><</span><span class="nx">unknown</span><span class="p">[]</span><span class="o">></span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nc">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="na">statement</span><span class="p">:</span> <span class="nx">Statement</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">prepare</span><span class="p">(</span><span class="nx">query</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="nf">isSelectQuery</span><span class="p">(</span><span class="nx">query</span><span class="p">))</span> <span class="p">{</span>
<span class="nf">resolve</span><span class="p">(</span><span class="nx">statement</span><span class="p">.</span><span class="nf">all</span><span class="p">());</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">info</span> <span class="o">=</span> <span class="nx">statement</span><span class="p">.</span><span class="nf">run</span><span class="p">();</span>
<span class="nf">resolve</span><span class="p">([]);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">private</span> <span class="nf">isSelectQuery</span><span class="p">(</span><span class="nx">query</span><span class="p">:</span> <span class="kr">string</span><span class="p">):</span> <span class="nx">boolean</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">query</span><span class="p">.</span><span class="nf">trim</span><span class="p">().</span><span class="nf">toLowerCase</span><span class="p">().</span><span class="nf">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">select</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>Now it's possible to run.</p>
<p>For example for request to SQLite database with simple schema of users, posts, comments and likes:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code> <span class="kd">const</span> <span class="nx">sqliteAdapter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SqliteAdapter</span><span class="p">({</span>
<span class="na">dbFilePath</span><span class="p">:</span> <span class="dl">"</span><span class="s2">./db.sqlite</span><span class="dl">"</span><span class="p">,</span>
<span class="p">});</span>
<span class="kd">const</span> <span class="nx">ormgpt</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">ormGPT</span><span class="p">({</span>
<span class="na">apiKey</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">OPENAI_API_KEY</span> <span class="o">||</span> <span class="dl">""</span><span class="p">,</span>
<span class="na">schemaFilePath</span><span class="p">:</span> <span class="dl">"</span><span class="s2">./schema.sql</span><span class="dl">"</span><span class="p">,</span>
<span class="na">dialect</span><span class="p">:</span> <span class="dl">"</span><span class="s2">postgres</span><span class="dl">"</span><span class="p">,</span>
<span class="na">dbEngineAdapter</span><span class="p">:</span> <span class="nx">sqliteAdapter</span><span class="p">,</span>
<span class="p">});</span>
<span class="nx">ormgpt</span><span class="p">.</span><span class="nf">query</span><span class="p">(</span><span class="dl">"</span><span class="s2">give me post with id 1, all comments for this post and user information about author</span><span class="dl">"</span><span class="p">);</span>
</code></pre>
</div>
<p>generated query:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight sql"><code><span class="k">SELECT</span>
<span class="n">p</span><span class="p">.</span><span class="n">id</span> <span class="k">AS</span> <span class="n">post_id</span><span class="p">,</span>
<span class="n">p</span><span class="p">.</span><span class="n">title</span><span class="p">,</span>
<span class="n">p</span><span class="p">.</span><span class="n">body</span><span class="p">,</span>
<span class="k">c</span><span class="p">.</span><span class="n">id</span> <span class="k">AS</span> <span class="n">comment_id</span><span class="p">,</span>
<span class="k">c</span><span class="p">.</span><span class="n">body</span> <span class="k">AS</span> <span class="n">comment_body</span><span class="p">,</span>
<span class="n">u</span><span class="p">.</span><span class="n">username</span> <span class="k">AS</span> <span class="n">author_username</span><span class="p">,</span>
<span class="n">u</span><span class="p">.</span><span class="n">email</span> <span class="k">AS</span> <span class="n">author_email</span>
<span class="k">FROM</span>
<span class="n">posts</span> <span class="n">p</span>
<span class="k">JOIN</span> <span class="n">comments</span> <span class="k">c</span> <span class="k">ON</span> <span class="n">p</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="k">c</span><span class="p">.</span><span class="n">post_id</span>
<span class="k">JOIN</span> <span class="n">users</span> <span class="n">u</span> <span class="k">ON</span> <span class="n">u</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">user_id</span>
<span class="k">WHERE</span>
<span class="n">p</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</code></pre>
</div>
<p>and after execution response from the database:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>[
{
post_id: 1,
title: 'Hello world!',
body: 'This is my first post!',
comment_id: 1,
comment_body: 'Hello world!',
author_username: 'test',
author_email: '[email protected]'
}
]
</code></pre>
</div>
<p>It's kind of hard to test such app because it's non-deterministic. The only way I thought about is to test short, precise statements like "create x with y and z" and then look up db if it's there. </p>
<p><a href="proxy.php?url=https://i.giphy.com/media/EBId5v0YNRyPGHytLK/giphy.gif" class="article-body-image-wrapper"><img src="proxy.php?url=https://i.giphy.com/media/EBId5v0YNRyPGHytLK/giphy.gif" alt="Db"></a></p>
<h3>
Conclusion
</h3>
<p>Here we come to the conclusion, of why this lib is useless for now. If you look for something more complex like joins, nested subqueries or engine-related queries with the current state of GPT is not possible to get results you can rely on. However, at least you can minimize randomness by being very strict about the requirements in your statement and decreasing "temperature" as low as 0 for deterministic results!</p>
<p>Anyway, as an experimental project, I decided to finish it. So the last part was to allow fine-tuning model parameters:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight typescript"><code><span class="k">export</span> <span class="kd">type</span> <span class="nx">ModelTuning</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">temperature</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="nl">max_tokens</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="nl">top_p</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="nl">frequency_penalty</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="nl">presence_penalty</span><span class="p">:</span> <span class="kr">number</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
</div>
<p>and prepare Postgres and MySQL adapters. The last part was to publish lib. The name ormGPT comes from ORM + GPT model but in fact it's neither orm nor query builder. The proper ORM should "map" the database into objects. Then maybe it's "intelligent" query builder? Also no. Query builder usually allows you to chain query object before generating sql. You can chain plain string, but is that enough? Maybe it should be chatGPTtoQueryFacade.js? </p>
<p>Too much thinking, not enough willingness. Published as ormGPT. </p>
<p>That's it. Tiny afternoon project, you shouldn't use in your production application. Or maybe you should? At the end you can tell your clients, you are using cutting-edge technologies and advanced AI.</p>
<p>You can find the lib on the NPM: <a href="proxy.php?url=https://www.npmjs.com/package/ormgpt" rel="noopener noreferrer">https://www.npmjs.com/package/ormgpt</a></p>
<p>or at the GitHub repository:</p>
<div class="ltag-github-readme-tag">
<div class="readme-overview">
<h2>
<img src="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo">
<a href="proxy.php?url=https://github.com/pilotpirxie" rel="noopener noreferrer">
pilotpirxie
</a> / <a href="proxy.php?url=https://github.com/pilotpirxie/ormGPT" rel="noopener noreferrer">
ormGPT
</a>
</h2>
<h3>
An ORM based on OpenAI that translates plain language into SQL queries and executes them on a database.
</h3>
</div>
<div class="ltag-github-body">
<div id="readme" class="md">
<div class="markdown-heading">
<h1 class="heading-element">ormGPT</h1>
</div>
<p>An ORM based on OpenAI that translates plain human language into SQL queries and executes them on a database.</p>
<p>Currently supports database dialects: MySQL, PostgreSQL, and SQLite.</p>
<p>Supported languages: English, German, French, Spanish, Polish, Italian, Dutch, Portuguese, Ukrainian, Arabic, Chinese, Japanese, Korean, Turkish and many more.</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight">
<pre>ormgpt.query(<span class="pl-s"><span class="pl-pds">"</span>give me post with id 1, all comments for this post and user information about author<span class="pl-pds">"</span></span>)<span class="pl-k">;</span></pre>
</div>
<p>Generated query:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto js-code-highlight">
<pre><span class="pl-k">SELECT</span>
<span class="pl-c1">p</span>.<span class="pl-c1">id</span> <span class="pl-k">AS</span> post_id,
<span class="pl-c1">p</span>.<span class="pl-c1">title</span>,
<span class="pl-c1">p</span>.<span class="pl-c1">body</span>,
<span class="pl-c1">c</span>.<span class="pl-c1">id</span> <span class="pl-k">AS</span> comment_id,
<span class="pl-c1">c</span>.<span class="pl-c1">body</span> <span class="pl-k">AS</span> comment_body,
<span class="pl-c1">u</span>.<span class="pl-c1">username</span> <span class="pl-k">AS</span> author_username,
<span class="pl-c1">u</span>.<span class="pl-c1">email</span> <span class="pl-k">AS</span> author_email
<span class="pl-k">FROM</span>
posts p
<span class="pl-k">JOIN</span> comments c <span class="pl-k">ON</span> <span class="pl-c1">p</span>.<span class="pl-c1">id</span> <span class="pl-k">=</span> <span class="pl-c1">c</span>.<span class="pl-c1">post_id</span>
<span class="pl-k">JOIN</span> users u <span class="pl-k">ON</span> <span class="pl-c1">u</span>.<span class="pl-c1">id</span> <span class="pl-k">=</span> <span class="pl-c1">p</span>.<span class="pl-c1">user_id</span>
<span class="pl-k">WHERE</span>
<span class="pl-c1">p</span>.<span class="pl-c1">id</span> <span class="pl-k">=</span> <span class="pl-c1">1</span>;</pre>
</div>
<p>Response:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight">
<pre><span class="pl-kos">[</span>
<span class="pl-kos">{</span>
<span class="pl-c1">post_id</span>: <span class="pl-c1">1</span><span class="pl-kos">,</span>
<span class="pl-c1">title</span>: <span class="pl-s">'Hello world!'</span><span class="pl-kos">,</span>
<span class="pl-c1">body</span>: </pre>…
</div>
</div>
</div>
<div class="gh-btn-container"><a class="gh-btn" href="proxy.php?url=https://github.com/pilotpirxie/ormGPT" rel="noopener noreferrer">View on GitHub</a></div>
</div>
webdevprogrammingaijavascriptHow to update a few years old outdated project in Node and React?Meat BoyThu, 24 Aug 2023 08:40:06 +0000
https://dev.to/meatboy/how-to-update-a-few-years-old-outdated-project-in-node-and-react-31jm
https://dev.to/meatboy/how-to-update-a-few-years-old-outdated-project-in-node-and-react-31jm<p>Navigating old Node.js dependencies can be confusing. In this article, I'll share how I decoded this challenge in a few-year-old repository using a custom tool—and how you too can benefit from my experience.</p>
<blockquote>
<p>tl;dr<br>
Use the tool <a href="proxy.php?url=https://www.npmjs.com/package/dependency-time-machine" rel="noopener noreferrer">dependency-time-machine</a> to quickly update dependencies one by one in chronological order. Most dependencies are compatible with other packages from a similar or pastime.<br>
This tool is intended to simulate the typical updating workflow as it was done regularly.</p>
<pre class="highlight plaintext"><code>
npx dependency-time-machine --update
</code></pre>
</blockquote>
<h3>
Outdated codebase
</h3>
<p><a href="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmesq95ooqrdd0uj2wh8.gif" class="article-body-image-wrapper"><img src="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmesq95ooqrdd0uj2wh8.gif" alt="GTA SA"></a></p>
<p>Recently I joined a new team with a great product but a highly outdated codebase. So my first task was to update dependencies and made changes so we can migrate from Node 16 to Node 18 and finally to Node 20. Some parts of the code were still relying on Node 14. The initial thought was to use <code>ncu</code> or <code>yarn upgrade-interactive</code> and update all patch versions since they shouldn't break anything if package developers were following the semver. But they didn't.</p>
<h3>
Dependency void
</h3>
<p>Many dependencies were not only "old" - this is not the problem, but they were incompatible with new Node versions and other dependencies which features we looked for. At the moment of doing this process, Node 16 becomes deprecated and Node 18 is going into maintenance. Having such an old codebase makes it hard to further develop and with backend part makes it also insecure and vulnerable.</p>
<p>Dependency management is not only about blindly updating, but also about knowing when it's beneficial to use or drop package and having common sense about long term tech debt.<br>
Sometimes, newer versions of a dependency can introduce breaking changes, reduced performance, or other issues. Before updating, developers should check changelogs, understand the implications of the update, and, ideally, test the update in a controlled environment before deploying it.</p>
<p>Over time, some dependencies might become redundant, or better alternatives might emerge. A good practice is to periodically review the project's dependencies to determine if they are still aligned with the project's needs. Additionally, if a package is no longer maintained or has known vulnerabilities, it might be wise to seek alternatives or drop it altogether.</p>
<p>Over-reliance on multiple dependencies can lead to technical debt. If not managed properly, this debt can accumulate, making future changes or updates cumbersome and risky. It's essential to strike a balance between leveraging existing solutions (dependencies) and the potential long-term costs associated with them.</p>
<p><a href="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi4mfd0a86vf44g5iaxs.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi4mfd0a86vf44g5iaxs.png" alt="Image description"></a></p>
<p>Going back to the case. Thankfully the team wrote plenty of good tests, both unit tests, some integration and a lot of end-to-end so after each update it was possible to check if something broke. At this point, I realized I have to go one-by-one dependency and look at which dependency will be compatible with others and SDK. </p>
<p>Some packages had phantom dependencies. They are indirect dependencies (but also not peerDependencies) and it is expected to have them installed and be available in certain directories. npm since v3 and yarn classic install dependencies in the flat structure of node_modules with nesting only sub-dependencies so the issue with phantom dependencies is hidden until changes in the package structure. pnpm - another package manager installs dependencies in a hidden directory and uses symlinks to make them available at node_modules levels. Also, it hides all sub-dependencies which brokes phantom dependencies early, leaving clean node_modules (IMO, that's good).</p>
<p><a href="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ob76w8dnlzbf8m3uvdy.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ob76w8dnlzbf8m3uvdy.png" alt="npm v2 vs v3"></a></p>
<p>Other problems were changes in Node SDK from 16 to 18. In the meantime, Node 17 introduced changes in the open SSL provider which brokes older webpack and DNS resolve mechanism from "by-default-ipv4" to "by-default-ipv6" which brokes usage of some backend and testing libraries.</p>
<h3>
dependency-time-machine
</h3>
<p>To maintain all this headache I wrote in my spare time a library called <a href="proxy.php?url=https://www.npmjs.com/package/dependency-time-machine" rel="noopener noreferrer">dependency-time-machine</a> which retrieves information about every package listed in package.json and its version. Then it creates a single timeline which is used to determine which library is the most behind and should be updated next.</p>
<p>I found libraries written at certain moments are compatible with other libraries at similar or previous timespan. So, for instance, library <code>[email protected]</code> that came when library <code>[email protected]</code> was already available makes it higher chance compatible than with the same library but with a higher version e.g. <code>[email protected]</code> that was released a year later than <code>[email protected]</code>.</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>
npx dependency-time-machine --timeline
</code></pre>
</div>
<p>Moreover, this replicates the natural process of updating dependencies. When you do this regularly you match existing libs with other existing libraries. So, the main problem that <code>dependency-time-machine</code> tries to solve is to reconstruct the process of natural updating.</p>
<p>And because it may be a lot of work, like in my case where I had to take care of over 200 packages (!) so to ease this process I put into tool <code>auto mode</code> which can find the next dependency to update before another dependency was released, install it and run tests. If tests pass, it will do the same over and over. If the tests fail it will stop so you can look closer and fix either codebase or test.</p>
<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>
npx dependency-time-machine --update --install --auto --install-script "yarn install" --test-script "yarn test"
</code></pre>
</div>
<p>Also, if you don't want to rely on auto-mode you can print the timeline in JSON and make decisions manually of updating dependencies. Other options allow you to exclude dependencies you don't want to update for some reason.</p>
<p>Going back to the story. It still took some time but at least I was more certain about the process and had the linear plan of work. After all, I wrote the document to describe the process so other team members know what's going on with the repository and discussed the process. Deployment went smoothly with only few minor issues in the meantime because most of the problems were spotted early thanks to willing help from team members.</p>
<p>Dependency management can be painful, but done regularly and with patience makes our future work easier. I hope someone finds this article and tool useful :)</p>
webdevjavascripttutorialreactData Structures using JavaScript for beginnersMeat BoyWed, 07 Dec 2022 10:13:53 +0000
https://dev.to/meatboy/definitive-guide-to-data-structures-using-javascript-for-beginners-1ea9
https://dev.to/meatboy/definitive-guide-to-data-structures-using-javascript-for-beginners-1ea9<p>Data structures are an essential part of computer science, as they provide the means to efficiently organize and store data. In the field of computer programming, data structures are used to implement algorithms and perform operations on data. JavaScript, a popular programming language, offers a number of built-in data structures that can be used to efficiently manipulate and store data.</p>
<p>This guide consists of introduction to:</p>
<ul>
<li>built-in objects</li>
<li>built-in arrays</li>
<li>linked list</li>
<li>double linked list</li>
<li>heap</li>
<li>stack</li>
<li>queue</li>
</ul>
<h3>
Built-in
</h3>
<p>One of the most commonly used data structures in JavaScript is the array. An array is a linear data structure that stores a collection of elements in a contiguous block of memory. The elements in an array can be of any data type, including numbers, strings, and objects.</p>
<p>Arrays in JavaScript are zero-indexed, which means that the first element in the array has an index of 0, the second element has an index of 1, and so on. To access an element in an array, we use its index. For example, to access the first element in an array named "myArray", we would use the following syntax:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="nx">myArray</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</code></pre>
</div>
<p>In addition to accessing elements by their index, JavaScript arrays also provide a number of useful methods that can be used to manipulate the data they contain. For example, the "push" method can be used to add new elements to the end of an array, and the "pop" method can be used to remove the last element from an array.</p>
<p>Another common data structure in JavaScript is the object. An object is a collection of key-value pairs, where the keys are used to identify the values. Objects in JavaScript are similar to dictionaries in other programming languages.</p>
<p>To create an object in JavaScript, we use the "object literal" syntax, which involves enclosing a list of key-value pairs in curly braces. For example, the following code creates an object named "myObject" that contains two key-value pairs:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="kd">let</span> <span class="nx">myObject</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">key1</span><span class="p">:</span> <span class="dl">"</span><span class="s2">value1</span><span class="dl">"</span><span class="p">,</span>
<span class="na">key2</span><span class="p">:</span> <span class="dl">"</span><span class="s2">value2</span><span class="dl">"</span>
<span class="p">};</span>
</code></pre>
</div>
<p>To access the values in an object, we use the dot notation or the square bracket notation. For example, to access the value associated with the "key1" key in the "myObject" object, we could use either of the following syntaxes:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="nx">myObject</span><span class="p">.</span><span class="nx">key1</span>
<span class="nx">myObject</span><span class="p">[</span><span class="dl">"</span><span class="s2">key1</span><span class="dl">"</span><span class="p">]</span>
</code></pre>
</div>
<p>In addition to the built-in data structures, JavaScript also allows developers to create their own data structures. For example, we could create a linked list data structure by defining a "Node" class that has properties for the data and a reference to the next node in the list, and a "LinkedList" class that has methods for adding, removing, and searching for nodes in the list.</p>
<p>Linked lists are useful for situations where we need to store a large amount of data and we don't know the size of the data in advance. Unlike arrays, linked lists do not have a fixed size, so they can grow and shrink dynamically to accommodate the data.</p>
<p>One of the main advantages of using data structures in JavaScript is that they provide a way to organize and store data in a way that is efficient and easy to work with. By using the built-in data structures and creating our own custom data structures, we can write code that is efficient, reusable, and maintainable.</p>
<p>In summary, data structures are an essential part of computer science and JavaScript provides a number of built-in data structures as well as the ability to create custom data structures. By using data structures, we can write code that is efficient, organized, and easy to work with.</p>
<h3>
Linked list
</h3>
<p>A linked list is a data structure that consists of a sequence of nodes, where each node contains a reference to the next node in the sequence. Linked lists are often used in computer programming because they provide a flexible and efficient way to store and manipulate data.</p>
<p>In a linked list, each node is an object that contains a value and a reference to the next node in the sequence. The first node in the linked list is called the "head" node, and the last node in the linked list is called the "tail" node.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="kd">class</span> <span class="nc">LinkedList</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">addToTail</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">newNode</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="p">,</span> <span class="na">next</span><span class="p">:</span> <span class="kc">null</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</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="nx">tail</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">removeHead</span><span class="p">()</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>One of the main advantages of linked lists is that they can be easily modified by adding or removing nodes from the list. For example, we can add a new node to the beginning of a linked list by simply setting the new node's "next" reference to the current head node, and then setting the linked list's head node to the new node. Similarly, we can remove a node from the beginning of a linked list by simply setting the linked list's head node to the current head node's "next" reference.</p>
<p>Another advantage of linked lists is that they can be easily traversed. To traverse a linked list, we simply start at the head node and follow the "next" references until we reach the tail node. This allows us to perform operations on all of the nodes in the list without having to know the size of the list in advance.</p>
<p>However, one disadvantage of linked lists is that they do not provide constant-time access to individual elements, like arrays do. To access a specific element in a linked list, we have to traverse the list from the beginning until we reach the desired element. This can be slow for large lists, especially if we want to access an element near the end of the list.</p>
<h3>
Double linked list
</h3>
<p>A double linked list is a variation of the linked list data structure that allows nodes to be traversed in both directions. In a double linked list, each node contains not only a reference to the next node in the sequence, but also a reference to the previous node in the sequence.</p>
<p>This allows us to traverse the list in either direction, starting at either the head or the tail node. It also allows us to easily remove a node from the middle of the list, by simply updating the previous node's "next" reference to point to the current node's "next" reference, and the next node's "previous" reference to point to the current node's "previous" reference.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="kd">class</span> <span class="nc">DoubleLinkedList</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">addToHead</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">newNode</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="p">,</span> <span class="na">next</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">,</span> <span class="na">prev</span><span class="p">:</span> <span class="kc">null</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="nx">newNode</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="nx">tail</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">addToTail</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">newNode</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">value</span><span class="p">,</span> <span class="na">next</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span> <span class="na">prev</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">tail</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="nx">tail</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="nx">newNode</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="nx">newNode</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">removeHead</span><span class="p">()</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">next</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="nx">head</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">head</span><span class="p">.</span><span class="nx">prev</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">removeTail</span><span class="p">()</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="nx">tail</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">const</span> <span class="nx">value</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">prev</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="nx">tail</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">tail</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<h3>
Stack
</h3>
<p>A stack is a data structure that provides two main operations: "push" and "pop". The "push" operation allows us to add an element to the top of the stack, and the "pop" operation allows us to remove the element at the top of the stack. Stacks are often used in computer programming because they provide a simple and efficient way to manage data.</p>
<p>One of the main characteristics of a stack is that it follows the "last-in, first-out" (LIFO) principle, which means that the last element that was added to the stack will be the first one to be removed. This is because the "pop" operation always removes the element at the top of the stack, and the "push" operation always adds an element to the top of the stack.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="kd">class</span> <span class="nc">Stack</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
<span class="nf">push</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="nx">item</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">pop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">pop</span><span class="p">();</span>
<span class="p">}</span>
<span class="nf">peek</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span>
<span class="p">}</span>
<span class="nf">isEmpty</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>A common example of a stack in computer programming is the call stack, which is used to keep track of the sequence of function calls in a program. When a function is called, its parameters and local variables are pushed onto the call stack, and when the function returns, its parameters and local variables are popped off the call stack.</p>
<h3>
Heap
</h3>
<p>A heap is a data structure that provides two main operations: "insert" and "extract". The "insert" operation allows us to add a new element to the heap, and the "extract" operation allows us to remove and return the largest or smallest element from the heap. Heaps are often used in computer programming because they provide a fast and efficient way to manage data.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="kd">class</span> <span class="nc">Heap</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">(</span><span class="nx">compareFn</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">compareFn</span> <span class="o">=</span> <span class="nx">compareFn</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span> <span class="o">=</span> <span class="p">[];</span>
<span class="p">}</span>
<span class="nf">add</span><span class="p">(</span><span class="nx">item</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="nx">item</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">heapifyUp</span><span class="p">();</span>
<span class="p">}</span>
<span class="c1">// Method to remove an item from the heap</span>
<span class="nf">remove</span><span class="p">()</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="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="kc">null</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="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">pop</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">removedItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">pop</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">heapifyDown</span><span class="p">();</span>
<span class="k">return</span> <span class="nx">removedItem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">heapifyUp</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">currentIndex</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">currentItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">];</span>
<span class="kd">let</span> <span class="nx">parentIndex</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">getParentIndex</span><span class="p">(</span><span class="nx">currentIndex</span><span class="p">);</span>
<span class="k">while </span><span class="p">(</span>
<span class="nx">parentIndex</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">&&</span>
<span class="k">this</span><span class="p">.</span><span class="nf">compareFn</span><span class="p">(</span><span class="nx">currentItem</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">parentIndex</span><span class="p">])</span> <span class="o">></span> <span class="mi">0</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">parentIndex</span><span class="p">];</span>
<span class="nx">currentIndex</span> <span class="o">=</span> <span class="nx">parentIndex</span><span class="p">;</span>
<span class="nx">currentItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">];</span>
<span class="nx">parentIndex</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">getParentIndex</span><span class="p">(</span><span class="nx">currentIndex</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">]</span> <span class="o">=</span> <span class="nx">currentItem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">heapifyDown</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">currentIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">currentItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">];</span>
<span class="kd">let</span> <span class="p">[</span><span class="nx">leftChildIndex</span><span class="p">,</span> <span class="nx">rightChildIndex</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">getChildIndices</span><span class="p">(</span><span class="nx">currentIndex</span><span class="p">);</span>
<span class="k">while </span><span class="p">(</span>
<span class="p">(</span><span class="nx">leftChildIndex</span> <span class="o"><</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">&&</span>
<span class="k">this</span><span class="p">.</span><span class="nf">compareFn</span><span class="p">(</span><span class="nx">currentItem</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">leftChildIndex</span><span class="p">])</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="o">||</span>
<span class="p">(</span><span class="nx">rightChildIndex</span> <span class="o"><</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">&&</span>
<span class="k">this</span><span class="p">.</span><span class="nf">compareFn</span><span class="p">(</span><span class="nx">currentItem</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">rightChildIndex</span><span class="p">])</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">swapIndex</span><span class="p">;</span>
<span class="k">if </span><span class="p">(</span>
<span class="nx">rightChildIndex</span> <span class="o"><</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">&&</span>
<span class="k">this</span><span class="p">.</span><span class="nf">compareFn</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">leftChildIndex</span><span class="p">],</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">rightChildIndex</span><span class="p">])</span> <span class="o"><</span>
<span class="mi">0</span>
<span class="p">)</span> <span class="p">{</span>
<span class="nx">swapIndex</span> <span class="o">=</span> <span class="nx">rightChildIndex</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">swapIndex</span> <span class="o">=</span> <span class="nx">leftChildIndex</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">swapIndex</span><span class="p">];</span>
<span class="nx">currentIndex</span> <span class="o">=</span> <span class="nx">swapIndex</span><span class="p">;</span>
<span class="nx">currentItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">];</span>
<span class="p">[</span><span class="nx">leftChildIndex</span><span class="p">,</span> <span class="nx">rightChildIndex</span><span class="p">]</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">getChildIndices</span><span class="p">(</span><span class="nx">currentIndex</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">[</span><span class="nx">currentIndex</span><span class="p">]</span> <span class="o">=</span> <span class="nx">currentItem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">getParentIndex</span><span class="p">(</span><span class="nx">childIndex</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nf">floor</span><span class="p">((</span><span class="nx">childIndex</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">getChildIndices</span><span class="p">(</span><span class="nx">parentIndex</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">[</span><span class="mi">2</span> <span class="o">*</span> <span class="nx">parentIndex</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="nx">parentIndex</span> <span class="o">+</span> <span class="mi">2</span><span class="p">];</span>
<span class="p">}</span>
</code></pre>
</div>
<p>One of the main characteristics of a heap is that it is a "complete binary tree", which means that all of the levels of the tree are fully filled, except possibly the last level, which is filled from left to right. This allows us to efficiently access and manipulate the elements in the heap.</p>
<p>Heaps can be either "max heaps" or "min heaps", depending on whether the largest or smallest element is at the root of the heap. In a max heap, the parent nodes are always greater than or equal to their child nodes, and in a min heap, the parent nodes are always less than or equal to their child nodes.</p>
<p>A common example of a heap in computer programming is the priority queue, which is used to store and manage a set of elements with associated priorities. In a priority queue, elements are added to the heap with their priorities, and the element with the highest priority is always extracted first.</p>
<h3>
Queue
</h3>
<p>A queue is a data structure that provides two main operations: "enqueue" and "dequeue". The "enqueue" operation allows us to add an element to the end of the queue, and the "dequeue" operation allows us to remove and return the element at the front of the queue. Queues are often used in computer programming because they provide a simple and efficient way to manage data.<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="c1">// Queue class</span>
<span class="kd">class</span> <span class="nc">Queue</span> <span class="p">{</span>
<span class="nf">constructor</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Heap</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=></span> <span class="nx">a</span><span class="p">.</span><span class="nx">priority</span> <span class="o">-</span> <span class="nx">b</span><span class="p">.</span><span class="nx">priority</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">enqueue</span><span class="p">(</span><span class="nx">item</span><span class="p">,</span> <span class="nx">priority</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">add</span><span class="p">({</span> <span class="nx">item</span><span class="p">,</span> <span class="nx">priority</span> <span class="p">});</span>
<span class="p">}</span>
<span class="nf">dequeue</span><span class="p">()</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="nf">isEmpty</span><span class="p">())</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">removedItem</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nf">remove</span><span class="p">();</span>
<span class="k">return</span> <span class="nx">removedItem</span><span class="p">.</span><span class="nx">item</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">isEmpty</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">items</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</div>
<p>One of the main characteristics of a queue is that it follows the "first-in, first-out" (FIFO) principle, which means that the first element that was added to the queue will be the first one to be removed. This is because the "dequeue" operation always removes the element at the front of the queue, and the "enqueue" operation always adds an element to the end of the queue.</p>
<p>A common example of a queue in computer programming is the message queue, which is used to store and manage messages that are being sent between different components of a system. In a message queue, messages are added to the queue with the "enqueue" operation, and they are removed and processed with the "dequeue" operation.</p>
<h3>
Summary
</h3>
<p>In summary, linked lists, double linked lists, stacks, heaps, and queues are all important data structures in computer science. They provide different ways to store and manipulate data, and they have different strengths and weaknesses. By understanding the characteristics and operations of these data structures, we can choose the right one for the task at hand and write efficient and effective code.</p>
aiwebdevproductivityReact Hooks - definitive guide for beginnersMeat BoyTue, 06 Dec 2022 14:35:42 +0000
https://dev.to/meatboy/react-hooks-definitive-guide-for-beginners-3817
https://dev.to/meatboy/react-hooks-definitive-guide-for-beginners-3817<p><strong>React hooks</strong> are a new feature introduced in React 16.8 that allows developers to use state and other React features without writing a class. This makes it possible to use React features in functional components, which are components written as JavaScript functions instead of classes.</p>
<h3>
useState
</h3>
<p>One of the most commonly used React hooks is the useState hook, which allows a functional component to have local state. Here is an example of how to use the useState hook to implement a simple counter component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</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="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="p">{</span><span class="nx">count</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">setCount</span><span class="p">(</span><span class="nx">count</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)}</span><span class="o">></span>
<span class="nx">Decrement</span>
<span class="p">}</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useState hook is called inside the Counter component to create a piece of state called count. The useState hook returns a pair of values: the current state value and a function to update it. In this case, the count variable holds the current value of the count state, and the setCount function is used to update the count state when a button is clicked.</p>
<p>Another useful React hook is the useEffect hook, which allows a functional component to perform side effects, such as making an API call or subscribing to a data source. Here is an example of how to use the useEffect hook to fetch data from an API and display it in a component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">DataFetcher</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">data</span><span class="p">,</span> <span class="nx">setData</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">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://example.com/api/data</span><span class="dl">'</span><span class="p">)</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=></span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">json</span> <span class="o">=></span> <span class="nx">setData</span><span class="p">(</span><span class="nx">json</span><span class="p">));</span>
<span class="p">},</span> <span class="p">[]);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="nx">data</span> <span class="o">&&</span> <span class="nx">data</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">item</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">p</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="o">></span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="p">))}</span>
<span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useEffect hook is called inside the DataFetcher component to perform a side effect when the component is rendered. The useEffect hook takes a function as an argument, which is called when the component is rendered. In this case, the function makes an API call to fetch some data and updates the component's state with the data when it is received.</p>
<p>React hooks provide a convenient and declarative way to use state and other React features in functional components. They can make code more readable and maintainable by avoiding the need to write complex class components.</p>
<h3>
useEffect
</h3>
<p>The useEffect hook is a built-in React hook that allows a functional component to perform side effects, such as making an API call or subscribing to a data source. It is called inside a functional component, and it takes a function as an argument, which is called when the component is rendered.</p>
<p>Here is an example of how to use the useEffect hook to fetch data from an API and display it in a component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">DataFetcher</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Declare a new piece of state to hold the fetched data</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">data</span><span class="p">,</span> <span class="nx">setData</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="c1">// Use the useEffect hook to perform a side effect (fetching data)</span>
<span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Call the API to fetch the data</span>
<span class="nx">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://example.com/api/data</span><span class="dl">'</span><span class="p">)</span>
<span class="c1">// Parse the response as JSON</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=></span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
<span class="c1">// Update the component's state with the fetched data</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">json</span> <span class="o">=></span> <span class="nx">setData</span><span class="p">(</span><span class="nx">json</span><span class="p">));</span>
<span class="p">},</span> <span class="p">[]);</span> <span class="c1">// The second argument to useEffect specifies when the effect should be executed</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="cm">/* Display the fetched data */</span><span class="p">}</span>
<span class="p">{</span><span class="nx">data</span> <span class="o">&&</span> <span class="nx">data</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">item</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">p</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="o">></span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="p">))}</span>
<span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useEffect hook is called inside the DataFetcher component to perform a side effect when the component is rendered. The useEffect hook takes a function as an argument, which is called when the component is rendered. In this case, the function makes an API call to fetch some data and updates the component's state with the data when it is received.</p>
<p>Have in mind this is just simple example. As <a class="mentioned-user" href="proxy.php?url=https://dev.to/brense">@brense</a> pointed 👏 </p>
<blockquote>
<p>Updating state asynchronously in useEffect without cleanup is no-bueno. When the component unmounts while your request is still executing, it will produce a nasty error when the request finishes and tries to update the state of your unmounted component. If you do anything asynchronously inside a useEffect you need to have a cleanup function that runs on unmount:<br>
</p>
</blockquote>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Do async stuff like fetch</span>
<span class="k">return</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Cleanup by cancelling your fetch</span>
<span class="p">}</span>
<span class="p">},</span> <span class="p">[])</span>
</code></pre>
</div>
<p>The <code>useEffect</code> hook can also be used to perform cleanup actions, such as canceling a subscription or removing an event listener, when a component is unmounted. This can be done by returning a function from the effect callback, which will be called when the component is unmounted.</p>
<p>Here is an example of how to use the useEffect hook to subscribe to a data source and perform cleanup when the component is unmounted:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">DataSubscriber</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Declare a new piece of state to hold the subscribed data</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">data</span><span class="p">,</span> <span class="nx">setData</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="c1">// Use the useEffect hook to perform a side effect (subscribing to a data source)</span>
<span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Create a new subscription to the data source</span>
<span class="kd">const</span> <span class="nx">subscription</span> <span class="o">=</span> <span class="nx">dataSource</span><span class="p">.</span><span class="nx">subscribe</span><span class="p">(</span><span class="nx">data</span> <span class="o">=></span> <span class="nx">setData</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
<span class="c1">// Return a cleanup function, which will be called when the component is unmounted</span>
<span class="k">return</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Cancel the subscription</span>
<span class="nx">subscription</span><span class="p">.</span><span class="nx">unsubscribe</span><span class="p">();</span>
<span class="p">};</span>
<span class="p">},</span> <span class="p">[]);</span> <span class="c1">// The second argument to useEffect specifies when the effect should be executed</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="cm">/* Display the subscribed data */</span><span class="p">}</span>
<span class="p">{</span><span class="nx">data</span> <span class="o">&&</span> <span class="nx">data</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">item</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">p</span> <span class="nx">key</span><span class="o">=</span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="o">></span><span class="p">{</span><span class="nx">item</span><span class="p">.</span><span class="nx">text</span><span class="p">}</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="p">))}</span>
<span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useEffect hook is called inside the DataSubscriber component to perform a side effect when the component is rendered. The useEffect hook takes a function as an argument, which is called when the component is rendered. In this case, the function creates a subscription to a data source and updates the component's state with the data when it is received. The useEffect hook also returns a cleanup function, which is called when the component is unmounted to cancel the subscription.</p>
<h3>
useContext
</h3>
<p>The useContext hook is a built-in React hook that allows a functional component to access the current value of a context, which is a way of passing data through the component tree without having to explicitly pass props at every level. It is called inside a functional component, and it takes a context object as an argument, which is created using the React.createContext method.</p>
<p>Here is an example of how to use the useContext hook to access the current theme in a component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useContext</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Create a new context object</span>
<span class="kd">const</span> <span class="nx">ThemeContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">light</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">ThemeChanger</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Use the useContext hook to access the current theme</span>
<span class="kd">const</span> <span class="nx">theme</span> <span class="o">=</span> <span class="nx">useContext</span><span class="p">(</span><span class="nx">ThemeContext</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">theme</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">theme</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useContext hook is called inside the ThemeChanger component to access the current value of the ThemeContext context. The useContext hook takes a context object as an argument, which is the ThemeContext object created at the top of the file. The useContext hook returns the current value of the context, which in this case is the current theme.</p>
<p>To provide a value for the context, a component can render a Provider component from the context object, passing the value as a prop. The Provider component will make the value available to all components in the component tree that are descendants of the Provider.</p>
<p>Here is an example of how to use the useContext hook with a Provider component to provide a value for the context:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useContext</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Create a new context object</span>
<span class="kd">const</span> <span class="nx">ThemeContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">light</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Use the useContext hook to access the current theme</span>
<span class="kd">const</span> <span class="nx">theme</span> <span class="o">=</span> <span class="nx">useContext</span><span class="p">(</span><span class="nx">ThemeContext</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">theme</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">theme</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">ThemeChanger</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="cm">/* Render a Provider component from the context object, passing the new theme as a prop */</span><span class="p">}</span>
<span class="o"><</span><span class="nx">ThemeContext</span><span class="p">.</span><span class="nx">Provider</span> <span class="nx">value</span><span class="o">=</span><span class="dl">"</span><span class="s2">dark</span><span class="dl">"</span><span class="o">></span>
<span class="o"><</span><span class="nx">App</span> <span class="o">/></span>
<span class="o"><</span><span class="sr">/ThemeContext.Provider</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useContext hook is called inside the App component to access the current value of the ThemeContext context. The ThemeChanger component renders a Provider component from the ThemeContext object, passing a new value for the theme as a prop. This makes the new theme available to the App component, which uses the useContext hook to access the theme. The useContext hook will return the new theme provided by the Provider, rather than the default light theme.</p>
<h3>
useReducer
</h3>
<p>The useReducer hook is a built-in React hook that allows a functional component to manage state in a complex component, or share state between multiple components. It is called inside a functional component, and it takes a reducer function and an initial state as arguments, and returns the current state and a dispatch method.</p>
<p>Here is an example of how to use the useReducer hook to manage state in a complex component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useReducer</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Define a reducer function to handle state updates</span>
<span class="kd">const</span> <span class="nx">reducer</span> <span class="o">=</span> <span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">action</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="nx">action</span><span class="p">.</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="dl">'</span><span class="s1">increment</span><span class="dl">'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">};</span>
<span class="k">case</span> <span class="dl">'</span><span class="s1">decrement</span><span class="dl">'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">count</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">};</span>
<span class="nl">default</span><span class="p">:</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Use the useReducer hook to manage state in the component</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">state</span><span class="p">,</span> <span class="nx">dispatch</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useReducer</span><span class="p">(</span><span class="nx">reducer</span><span class="p">,</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="mi">0</span> <span class="p">});</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">state</span><span class="p">.</span><span class="nx">count</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">dispatch</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">increment</span><span class="dl">'</span> <span class="p">})}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">dispatch</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">decrement</span><span class="dl">'</span> <span class="p">})}</span><span class="o">></span>
<span class="nx">Decrement</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useReducer hook is called inside the Counter component to manage state in the component. The useReducer hook takes a reducer function and an initial state as arguments, and returns the current state and a dispatch method. The reducer function defines how the state should be updated in response to actions, and the initial state sets the initial value of the state.</p>
<p>The Counter component uses the useReducer hook to access the current state and dispatch method, and uses them to display the current count and handle button clicks to increment or decrement the count. When a button is clicked, the component calls the dispatch method with an action object, which is passed to the reducer function to update the state.</p>
<p>The useReducer hook can also be used to share state between multiple components. This can be done by creating a context object and using the useReducer hook in a component higher up in the component tree to manage the shared state. The current state and dispatch method can then be accessed using the useContext hook in descendant components.</p>
<p>Here is an example of how to use the useReducer hook to share state between multiple components:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useReducer</span><span class="p">,</span> <span class="nx">useContext</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="c1">// Create a new context object</span>
<span class="kd">const</span> <span class="nx">CounterContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">();</span>
<span class="c1">// Define a reducer function to handle state updates</span>
<span class="kd">const</span> <span class="nx">reducer</span> <span class="o">=</span> <span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">action</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">switch</span> <span class="p">(</span><span class="nx">action</span><span class="p">.</span><span class="nx">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="dl">'</span><span class="s1">increment</span><span class="dl">'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">count</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">};</span>
<span class="k">case</span> <span class="dl">'</span><span class="s1">decrement</span><span class="dl">'</span><span class="p">:</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">count</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">};</span>
<span class="nl">default</span><span class="p">:</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Use the useContext hook to access the current count and dispatch method</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">count</span><span class="p">,</span> <span class="nx">dispatch</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">useContext</span><span class="p">(</span><span class="nx">CounterContext</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">count</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">dispatch</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">increment</span><span class="dl">'</span> <span class="p">})}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">dispatch</span><span class="p">({</span> <span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">decrement</span><span class="dl">'</span> <span class="p">})}</span><span class="o">></span>
<span class="nx">Decrement</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
<span class="kd">const</span> <span class="nx">CounterProvider</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Use the useReducer hook to manage state in the component</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">state</span><span class="p">,</span> <span class="nx">dispatch</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useReducer</span><span class="p">(</span><span class="nx">reducer</span><span class="p">,</span> <span class="p">{</span> <span class="na">count</span><span class="p">:</span> <span class="mi">0</span> <span class="p">});</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="p">{</span><span class="cm">/* Render a Provider component from the context object, passing the current state and dispatch method as props */</span><span class="p">}</span>
<span class="o"><</span><span class="nx">CounterContext</span><span class="p">.</span><span class="nx">Provider</span> <span class="nx">value</span><span class="o">=</span><span class="p">{{</span> <span class="na">count</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">count</span><span class="p">,</span> <span class="nx">dispatch</span> <span class="p">}}</span><span class="o">></span>
<span class="o"><</span><span class="nx">App</span> <span class="o">/></span>
<span class="o"><</span><span class="sr">/CounterContext.Provider</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useReducer hook is called inside the CounterProvider component to manage state in the component. The useReducer hook takes a reducer function and an initial state as arguments, and returns the current state and a dispatch method. The CounterProvider component uses the useReducer hook to access the current state and dispatch method, and renders a Provider component from the CounterContext object, passing the current state and dispatch method as props.</p>
<p>The App component uses the useContext hook to access the current count and dispatch method from the CounterContext context. The useContext hook takes the CounterContext object as an argument, and returns the current count and dispatch method provided by the Provider component. The App component uses the count and dispatch method to display the current count and handle button clicks to increment or decrement the count. When a button is clicked, the component calls the dispatch method with an action object, which is passed to the reducer function to update the state.</p>
<h3>
useCallback
</h3>
<p>The useCallback hook is a built-in React hook that allows a functional component to memoize a callback function, so that the function is not recreated on every render. It is called inside a functional component, and it takes a callback function and an array of dependencies as arguments, and returns a memoized callback function.</p>
<p>Here is an example of how to use the useCallback hook to memoize a callback function:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useCallback</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Declare a new piece of state to hold the count</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="c1">// Use the useCallback hook to memoize the incrementCount callback function</span>
<span class="kd">const</span> <span class="nx">incrementCount</span> <span class="o">=</span> <span class="nx">useCallback</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">setCount</span><span class="p">(</span><span class="nx">prevCount</span> <span class="o">=></span> <span class="nx">prevCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">},</span> <span class="p">[]);</span> <span class="c1">// The second argument to useCallback specifies the dependencies of the callback function</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">count</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">incrementCount</span><span class="p">}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useCallback hook is called inside the Counter component to memoize the incrementCount callback function. The useCallback hook takes a callback function and an array of dependencies as arguments, and returns a memoized callback function. In this case, the incrementCount callback function updates the count by calling setCount, and the dependencies array is empty, so the callback function will only be recreated when the dependencies change.</p>
<p>The Counter component uses the useCallback hook to memoize the incrementCount callback function, and passes the memoized callback function to the onClick event handler of the Increment button. When the button is clicked, the incrementCount callback function is called, and the count is updated. Because the incrementCount callback function is memoized, it will not be recreated on every render, which can improve performance.</p>
<h3>
useMemo
</h3>
<p>The useMemo hook is a built-in React hook that allows a functional component to memoize a value, so that the value is not recalculated on every render. It is called inside a functional component, and it takes a value-calculating function and an array of dependencies as arguments, and returns the memoized value.</p>
<p>Here is an example of how to use the useMemo hook to memoize a value:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useMemo</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Counter</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Declare a new piece of state to hold the count</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="c1">// Use the useMemo hook to memoize the result of the square calculation</span>
<span class="kd">const</span> <span class="nx">square</span> <span class="o">=</span> <span class="nx">useMemo</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Calculate the square of the count</span>
<span class="k">return</span> <span class="nx">count</span> <span class="o">*</span> <span class="nx">count</span><span class="p">;</span>
<span class="p">},</span> <span class="p">[</span><span class="nx">count</span><span class="p">]);</span> <span class="c1">// The second argument to useMemo specifies the dependencies of the value calculation</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">count</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">square</span> <span class="k">of</span> <span class="nx">the</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">square</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">setCount</span><span class="p">(</span><span class="nx">prevCount</span> <span class="o">=></span> <span class="nx">prevCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useMemo hook is called inside the Counter component to memoize the result of the square calculation. The useMemo hook takes a value-calculating function and an array of dependencies as arguments, and returns the memoized value. In this case, the value-calculating function calculates the square of the count, and the dependencies array contains the count state, so the value will only be recalculated when the count changes.</p>
<h3>
useImperativeHandle
</h3>
<p>The useImperativeHandle hook is a built-in React hook that allows a functional component to expose a custom imperative API to its parent component. It is called inside a functional component that is wrapped in a forwardRef callback, and it takes an object containing the custom imperative methods as an argument, and returns nothing.</p>
<p>Here is an example of how to use the useImperativeHandle hook to expose a custom imperative API to a parent component:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useRef</span><span class="p">,</span> <span class="nx">forwardRef</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">TextInput</span> <span class="o">=</span> <span class="nx">forwardRef</span><span class="p">((</span><span class="nx">props</span><span class="p">,</span> <span class="nx">ref</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Create a ref to store the input element</span>
<span class="kd">const</span> <span class="nx">inputRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="c1">// Use the useImperativeHandle hook to expose a custom imperative API</span>
<span class="nx">useImperativeHandle</span><span class="p">(</span><span class="nx">ref</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="c1">// Define a focus method that sets focus on the input element</span>
<span class="na">focus</span><span class="p">:</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">inputRef</span><span class="p">.</span><span class="nx">current</span><span class="p">.</span><span class="nx">focus</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">});</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">input</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">inputRef</span><span class="p">}</span> <span class="sr">/</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">});</span>
</code></pre>
</div>
<p>In this example, the useImperativeHandle hook is called inside the TextInput component to expose a custom imperative API to the parent component. The useImperativeHandle hook takes an object containing the custom imperative methods as an argument, and returns nothing. In this case, the object contains a focus method that sets focus on the input element.</p>
<p>The TextInput component is a functional component that is wrapped in a forwardRef callback, which allows the parent component to access the ref passed to the TextInput component. The useImperativeHandle hook is called inside the TextInput component, and it is passed the ref object provided by the forwardRef callback. This allows the useImperativeHandle hook to access the ref object and attach the custom imperative methods to it.</p>
<p>Here is an example of how to use the ref object passed to the TextInput component to call the custom imperative focus method:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useRef</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Create a ref to store the TextInput instance</span>
<span class="kd">const</span> <span class="nx">inputRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">TextInput</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">inputRef</span><span class="p">}</span> <span class="sr">/</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">inputRef</span><span class="p">.</span><span class="nx">current</span><span class="p">.</span><span class="nx">focus</span><span class="p">()}</span><span class="o">></span>
<span class="nx">Focus</span> <span class="nx">the</span> <span class="nx">input</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the App component uses the useRef hook to create a ref to store the TextInput instance.</p>
<h3>
useLayoutEffect
</h3>
<p>The useLayoutEffect hook is a built-in React hook that allows a functional component to perform layout effects, such as measuring the dimensions of an element. It is called inside a functional component, and it takes a callback function that performs the layout effects as an argument, and returns nothing.</p>
<p>The main advantage of using the useLayoutEffect hook is that it runs synchronously after the browser has painted the layout, so it can be used to update the layout in response to a change in state or props. This is different from the useEffect hook, which runs asynchronously after the browser has painted the layout, so it cannot be used to update the layout.</p>
<p>Here is an example of how to use the useLayoutEffect hook to measure the dimensions of an element:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useRef</span><span class="p">,</span> <span class="nx">useLayoutEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">MeasureElement</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Create a ref to store the element</span>
<span class="kd">const</span> <span class="nx">elementRef</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">(</span><span class="kc">null</span><span class="p">);</span>
<span class="c1">// Use the useLayoutEffect hook to measure the element's dimensions</span>
<span class="nx">useLayoutEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Measure the element's dimensions using the getBoundingClientRect method</span>
<span class="kd">const</span> <span class="nx">rect</span> <span class="o">=</span> <span class="nx">elementRef</span><span class="p">.</span><span class="nx">current</span><span class="p">.</span><span class="nx">getBoundingClientRect</span><span class="p">();</span>
<span class="c1">// Log the dimensions of the element</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Width: </span><span class="p">${</span><span class="nx">rect</span><span class="p">.</span><span class="nx">width</span><span class="p">}</span><span class="s2">, Height: </span><span class="p">${</span><span class="nx">rect</span><span class="p">.</span><span class="nx">height</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">});</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">elementRef</span><span class="p">}</span><span class="o">></span>
<span class="p">...</span>
<span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useLayoutEffect hook is called inside the MeasureElement component to measure the dimensions of the div element. The useLayoutEffect hook takes a callback function that performs the layout effects as an argument, and returns nothing. In this case, the callback function measures the dimensions of the div element using the getBoundingClientRect method, and logs the dimensions to the console.</p>
<p>The MeasureElement component uses the useRef hook to create a ref to store the div element, and passes the ref to the div element as the ref prop. The useLayoutEffect hook is called inside the MeasureElement component, and it is passed the ref to the div element. This allows the useLayoutEffect hook to access the div element and measure its dimensions.</p>
<p>When the MeasureElement component is rendered, the useLayoutEffect hook runs synchronously after the browser has painted the layout, so it can measure the dimensions of the div element and log the dimensions to the console. This allows the MeasureElement component to update the layout in response to a change in state or props, without causing a layout thrashing.</p>
<h3>
useDebugValue
</h3>
<p>The useDebugValue hook is a built-in React hook that allows a functional component to display a custom label in the React DevTools. It is called inside a functional component, and it takes a value that represents the current state or props of the component as an argument, and returns nothing.</p>
<p>The main advantage of using the useDebugValue hook is that it allows a developer to see the current state or props of a functional component in the React DevTools, which can be useful for debugging and understanding the behavior of the component. This is especially useful for components that are wrapped in higher-order components, such as connect from the Redux library, because it allows the developer to see the values passed to the wrapped component.</p>
<p>Here is an example of how to use the useDebugValue hook to display a custom label in the React DevTools:<br>
</p>
<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useDebugValue</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">Counter</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="c1">// Declare a new piece of state to hold the count</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">count</span><span class="p">,</span> <span class="nx">setCount</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="c1">// Use the useDebugValue hook to display the count in the React DevTools</span>
<span class="nx">useDebugValue</span><span class="p">(</span><span class="nx">count</span><span class="p">);</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">p</span><span class="o">></span><span class="nx">The</span> <span class="nx">current</span> <span class="nx">count</span> <span class="nx">is</span> <span class="p">{</span><span class="nx">count</span><span class="p">}.</span><span class="o"><</span><span class="sr">/p</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span> <span class="o">=></span> <span class="nx">setCount</span><span class="p">(</span><span class="nx">prevCount</span> <span class="o">=></span> <span class="nx">prevCount</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)}</span><span class="o">></span>
<span class="nx">Increment</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span> <span class="p">);</span>
<span class="p">};</span>
</code></pre>
</div>
<p>In this example, the useDebugValue hook is called inside the Counter component to display the current count in the React DevTools. The useDebugValue hook takes a value that represents the current state or props of the component as an argument, and returns nothing. In this case, the value is the count state, so the useDebugValue hook will display the current count in the React DevTools.</p>
<p>When the Counter component is rendered, the useDebugValue hook will display the current count in the React DevTools, under the label "Counter". This allows the developer to see the current count of the Counter component in the React DevTools, which can be useful for debugging and understanding the behavior of the component.</p>
<p>To sum up, there are several advantages to using React hooks in functional components. Some of the main advantages include:</p>
<ul>
<li>Improved performance: Hooks allow functional components to manage state and perform side effects, without requiring the overhead of class components. This can improve the performance of the application by reducing the amount of code that needs to be executed.</li>
<li>Cleaner code: Hooks allow functional components to manage state and perform side effects using a simple and declarative syntax. This can make the code easier to read and understand, and can make it easier to refactor and maintain.</li>
<li>Reusable logic: Hooks can be extracted from functional components and shared across multiple components, allowing developers to reuse common logic and avoid duplication. This can improve the modularity and maintainability of the application.</li>
<li>Better composition: Hooks allow functional components to be composed in a more flexible and powerful way, allowing developers to create custom hooks that combine multiple hooks in a reusable and composable way. This can make it easier to create complex and flexible components, without sacrificing readability and maintainability.</li>
</ul>
<p>Overall, the use of React hooks in functional components can improve the performance, cleanliness, and reusability of the code, and can make it easier to create complex and flexible components.</p>
javascriptreactwebdevbeginnersRecommendation system #4 - Algorithm and final resultsMeat BoyThu, 08 Sep 2022 04:28:40 +0000
https://dev.to/meatboy/writing-recommendation-system-3-algorithm-and-final-results-5c70
https://dev.to/meatboy/writing-recommendation-system-3-algorithm-and-final-results-5c70<p>In the previous <a href="proxy.php?url=https://dev.to/meatboy/writing-recommendation-system-2-redis-node-architecture-kje">post</a> we looked closer at the algorithm and connection between Redis and Node. Today, quickly I summarize how the recommendation is made.</p>
<p>A single recommendation is an overlap between item tags and actor tag-event interactions. </p>
<p>For example items:<br>
Titanic has tags: drama, tragedy, history, action. <br>
Merlin has tags: adventure, fantasy, history, wizards. <br>
Harry Potter has tags: adventure, fantasy, action, wizards. </p>
<p>Actor - user - previously could interact with some films:<br>
Liked a film with tags: action, fantasy<br>
Add to favourite film with tags: action, fantasy<br>
Liked a film with tags: history, action, comedy<br>
Liked a film with tags: adventure, fantasy, dragons<br>
Liked a film with tags: wizards, history, action<br>
Add to favourite film with tags: drama, wizards, fantasy</p>
<p>Now let's say, each like is a weight of 1 and each favourite is a weight of 3. The Sum of overlap (with or without duplication, with or without clamp to 1) divided by the maximum value per film is our overlap. And the higher it is, the stronger recommendation is.</p>
<p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--07sP9gMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mqqdre53kg68btfzf7ca.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--07sP9gMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mqqdre53kg68btfzf7ca.png" alt="Spreadsheet" width="538" height="530"></a><br>
Example with duplication</p>
<p>To make sure tags are still relevant, they have an expiration time. So as the interest may change, they expire and will be replaced with new tags. In this approach is also worth to notice the more keywords items have, the more suggestion is precise. </p>
<h3>
Demo of film recommendations with 10,000 videos
</h3>
<p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/_m1BandnVsQ">
</iframe>
</p>
<p>And the source code:<br>
</p>
<div class="ltag-github-readme-tag">
<div class="readme-overview">
<h2>
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo">
<a href="proxy.php?url=https://github.com/pilotpirxie">
pilotpirxie
</a> / <a href="proxy.php?url=https://github.com/pilotpirxie/recommendation">
recommendation
</a>
</h2>
<h3>
🦝 Simple and open source recommendation system
</h3>
</div>
<div class="ltag-github-body">
<div id="readme" class="md">
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/logo.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--B3jAFkJ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/logo.png" width="250" alt="Recommendation"></a>
</p>
<h1>
recommendation</h1>
<p>Open source recommendation system based on time-series data and statistical analysis. Written in <code>TypeScript</code> and <code>Node.js</code> using <code>Redis</code> for storage. The recommendation system uses the <code>Jaccard index</code> to calculate the intersection between two sets. One set is represented by the maximum possible sum of tag score and the other set is the score sum of user events per tag. The higher the Jaccard index, the higher the recommendation. It uses numbers to represent sets to increase performance.</p>
<h2>
Features</h2>
<ul>
<li>Use tag score and Jaccard index</li>
<li>Content-based filtering</li>
<li>Event-driven powered engine</li>
<li>Naive exploration of new tags</li>
<li>Suitable for product and content recommendation</li>
<li>Fine-tuning of tag weights</li>
<li>Minimalist and lightweight</li>
<li>Written in TypeScript and Node.js</li>
</ul>
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/architecture.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--StXCjTTG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/architecture.png" width="500" alt="Recommendation Architecture"></a>
</p>
<h2>
Overview video</h2>
<p>
<a href="proxy.php?url=https://www.youtube.com/watch?v=_m1BandnVsQ" rel="nofollow">
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--dpw0sr6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/thumbnail.png" width="500" alt="Video">
</a>
</p>
<h2>
How it works</h2>
<h3>
How the data is stored:</h3>
<ul>
<li>Actors are stored in Redis as simple <code>String</code> keys with create date <code>timestamps</code> as value.</li>
<li>Items are <code>Set</code> type with <code>tags</code> as members. The item may have…</li>
</ul>
</div>
<br>
</div>
<br>
<div class="gh-btn-container"><a class="gh-btn" href="proxy.php?url=https://github.com/pilotpirxie/recommendation">View on GitHub</a></div>
<br>
</div>
<br>
<p>That was the last post about my Redis Hackathon journey. It was fun to participate and learn more about the technical aspects of Redis. Also, the hackathon allowed me to stay focused and finish another side project! What a wonderful event! ;)</p>
redishackathontypescriptnodeshowdevRecommendation systemMeat BoySun, 28 Aug 2022 10:04:00 +0000
https://dev.to/meatboy/recommendation-system-2l4n
https://dev.to/meatboy/recommendation-system-2l4n<h3>
Overview of My Submission
</h3>
<p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9UYn61Hd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kf8cthjn8yasqvty206p.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--9UYn61Hd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kf8cthjn8yasqvty206p.png" alt="Project logo" width="880" height="584"></a></p>
<h4>
Recommendation System
</h4>
<p>Open source recommendation system based on time-series data and statistical analysis. Written in TypeScript and Node.js using Redis for storage. The recommendation system uses the Jaccard index to calculate the intersection between two sets. One set is represented by the maximum possible sum of tag score and the other set is the score sum of user events per tag. The higher the Jaccard index, the higher the recommendation. It uses numbers to represent sets to increase performance.</p>
<h2>
Features
</h2>
<ul>
<li>Use tag score and Jaccard index</li>
<li>Content-based filtering</li>
<li>Event-driven powered engine</li>
<li>Naive exploration of new tags</li>
<li>Suitable for product and content recommendation</li>
<li>Fine-tuning of tag weights</li>
<li>Minimalist and lightweight</li>
<li>Written in TypeScript and Node.js</li>
</ul>
<h2>
How it works
</h2>
<h3>
How the data is stored:
</h3>
<ul>
<li>Actors are stored in Redis as simple <code>String</code> keys with create date <code>timestamps</code> as value.</li>
<li>Items are <code>Set</code> type with <code>tags</code> as members. The item may have multiple tags.</li>
<li>Events are <code>String</code> type with <code>actorId:id:tag:timestamp:ttl</code> and an expire attribute set to ensure freshness of recommendations.</li>
</ul>
<h3>
How the data is accessed:
</h3>
<ul>
<li>Get the actor with events
<ul>
<li>Check if the actor exists with <code>EXISTS actor:${id}</code>
</li>
<li>Get all user events with <code>SCAN ${loop cursor} MATCH actor:${id}</code>
</li>
</ul>
</li>
<li>Delete a single actor
<ul>
<li>Scan for each related to actor key <code>SCAN ${loop cursor} MATCH actor:${id}*</code>
</li>
<li>For each key delete with <code>DEL ${key}</code>
</li>
</ul>
</li>
<li>Add a single actor
<ul>
<li>Scan for each related to actor key <code>SCAN ${loop cursor} MATCH actor:${id}*</code>
</li>
<li>For each key delete with <code>DEL ${key}</code>
</li>
<li>Add new actor with <code>SET actor:${id} ${Date.now().toString()}</code>
</li>
</ul>
</li>
<li>Add a single event
<ul>
<li>Check if actor exists if flag is set using <code>EXISTS actor:${id}</code>
</li>
<li>Add event with <code>SET actor:${id}:${tag}:${date}:${ttl} ${score}</code>
</li>
<li>If <code>TTL</code> has been provided, set expiration for event with <code>EXPIRE actor:${id}:${tag}:${date}:${ttl} ${ttl}</code>
</li>
</ul>
</li>
<li>Get all items with tags
<ul>
<li>Get all items with <code>SCAN ${loop cursor} MATCH item:*</code>
</li>
<li>For each item get all tags with <code>SMEMBERS ${itemKey}</code>
</li>
</ul>
</li>
<li>Get a single item with tags
<ul>
<li>Get all tags of item with <code>SMEMBERS item:${id}</code>
</li>
</ul>
</li>
<li>Delete single item
<ul>
<li>Call with <code>DEL item:${id}</code>
</li>
</ul>
</li>
<li>Add a single item
<ul>
<li>Check if item already exists <code>EXISTS item:${id}</code>
</li>
<li>If so, then remove <code>DEL item:${id}</code>
</li>
<li>And add item with tags <code>SADD item:${id} ${tags}</code>
</li>
</ul>
</li>
</ul>
<div class="ltag-github-readme-tag">
<div class="readme-overview">
<h2>
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo">
<a href="proxy.php?url=https://github.com/pilotpirxie">
pilotpirxie
</a> / <a href="proxy.php?url=https://github.com/pilotpirxie/recommendation">
recommendation
</a>
</h2>
<h3>
🦝 Simple and open source recommendation system
</h3>
</div>
<div class="ltag-github-body">
<div id="readme" class="md">
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/logo.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--B3jAFkJ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/logo.png" width="250" alt="Recommendation"></a>
</p>
<h1>
recommendation</h1>
<p>Open source recommendation system based on time-series data and statistical analysis. Written in <code>TypeScript</code> and <code>Node.js</code> using <code>Redis</code> for storage. The recommendation system uses the <code>Jaccard index</code> to calculate the intersection between two sets. One set is represented by the maximum possible sum of tag score and the other set is the score sum of user events per tag. The higher the Jaccard index, the higher the recommendation. It uses numbers to represent sets to increase performance.</p>
<h2>
Features</h2>
<ul>
<li>Use tag score and Jaccard index</li>
<li>Content-based filtering</li>
<li>Event-driven powered engine</li>
<li>Naive exploration of new tags</li>
<li>Suitable for product and content recommendation</li>
<li>Fine-tuning of tag weights</li>
<li>Minimalist and lightweight</li>
<li>Written in TypeScript and Node.js</li>
</ul>
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/architecture.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--StXCjTTG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/architecture.png" width="500" alt="Recommendation Architecture"></a>
</p>
<h2>
Overview video</h2>
<p>
<a href="proxy.php?url=https://www.youtube.com/watch?v=_m1BandnVsQ" rel="nofollow">
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--dpw0sr6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/thumbnail.png" width="500" alt="Video">
</a>
</p>
<h2>
How it works</h2>
<h3>
How the data is stored:</h3>
<ul>
<li>Actors are stored in Redis as simple <code>String</code> keys with create date <code>timestamps</code> as value.</li>
<li>Items are <code>Set</code> type with <code>tags</code> as members. The item may have…</li>
</ul>
</div>
</div>
<div class="gh-btn-container"><a class="gh-btn" href="proxy.php?url=https://github.com/pilotpirxie/recommendation">View on GitHub</a></div>
</div>
<h3>
Video - Demo of film recommendations
</h3>
<p><iframe width="710" height="399" src="proxy.php?url=https://www.youtube.com/embed/_m1BandnVsQ">
</iframe>
</p>
<h3>
Submission Category:
</h3>
<p>Minimalism Magicians</p>
<p>Replaces time series database for high volume input of actor (e.g. user) events and OLAP operations to calculate recommendations. Have in mind the time limitation of hackathon so take this statement with a pinch of salt ;)</p>
<h3>
Language Used
</h3>
<p>TypeScript</p>
<h3>
Link to Code
</h3>
<p><a href="proxy.php?url=https://github.com/pilotpirxie/recommendation">https://github.com/pilotpirxie/recommendation</a></p>
<h3>
Additional Resources / Info
</h3>
<p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--OmPi1-cS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pm0k017kayjds0lq1a35.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--OmPi1-cS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pm0k017kayjds0lq1a35.png" alt="Architecture" width="621" height="922"></a></p>
<h3>
Collaborators
</h3>
<div class="ltag__user ltag__user__id__267194">
<a href="proxy.php?url=/meatboy" class="ltag__user__link profile-image-link">
<div class="ltag__user__pic">
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--j4Yq0a-r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--njTUUUVx--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/267194/3db4562b-8873-4e13-be10-eee8e200422d.jpg" alt="meatboy image">
</div>
</a>
<div class="ltag__user__content">
<h2>
<a class="ltag__user__link" href="proxy.php?url=/meatboy">Meat Boy</a>Follow
</h2>
<div class="ltag__user__summary">
<a class="ltag__user__link" href="proxy.php?url=/meatboy">AWS, Web & Mobile Dev</a>
</div>
</div>
</div>
<ul>
<li><em>Check out <a href="proxy.php?url=https://redis.io/docs/stack/get-started/clients/#high-level-client-libraries">Redis OM</a>, client libraries for working with Redis as a multi-model database.</em></li>
<li><em>Use <a href="proxy.php?url=https://redis.info/redisinsight">RedisInsight</a> to visualize your data in Redis.</em></li>
<li><em>Sign up for a <a href="proxy.php?url=https://redis.info/try-free-dev-to">free Redis database</a>.</em></li>
</ul>
redishackathonRecommendation system #3 - Redis & Node ArchitectureMeat BoySun, 28 Aug 2022 08:58:00 +0000
https://dev.to/meatboy/writing-recommendation-system-2-redis-node-architecture-kje
https://dev.to/meatboy/writing-recommendation-system-2-redis-node-architecture-kje<p>It is quite some time since the last time when I wrote about business requirements and goals of the recommendation system. That because I had busy private life recently. Thankfully, I am back and here is the next part of my Redis Hackathon journey.</p>
<p>You can find source code of this project on GitHub:<br>
</p>
<div class="ltag-github-readme-tag">
<div class="readme-overview">
<h2>
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo">
<a href="proxy.php?url=https://github.com/pilotpirxie">
pilotpirxie
</a> / <a href="proxy.php?url=https://github.com/pilotpirxie/recommendation">
recommendation
</a>
</h2>
<h3>
🦝 Simple and open source recommendation system
</h3>
</div>
<div class="ltag-github-body">
<div id="readme" class="md">
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/logo.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--B3jAFkJ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/logo.png" width="250" alt="Recommendation"></a>
</p>
<h1>
recommendation</h1>
<p>Open source recommendation system based on time-series data and statistical analysis. Written in <code>TypeScript</code> and <code>Node.js</code> using <code>Redis</code> for storage. The recommendation system uses the <code>Jaccard index</code> to calculate the intersection between two sets. One set is represented by the maximum possible sum of tag score and the other set is the score sum of user events per tag. The higher the Jaccard index, the higher the recommendation. It uses numbers to represent sets to increase performance.</p>
<h2>
Features</h2>
<ul>
<li>Use tag score and Jaccard index</li>
<li>Content-based filtering</li>
<li>Event-driven powered engine</li>
<li>Naive exploration of new tags</li>
<li>Suitable for product and content recommendation</li>
<li>Fine-tuning of tag weights</li>
<li>Minimalist and lightweight</li>
<li>Written in TypeScript and Node.js</li>
</ul>
<p>
<a rel="noopener noreferrer" href="proxy.php?url=https://github.com/pilotpirxie/recommendationimg/architecture.png"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--StXCjTTG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/architecture.png" width="500" alt="Recommendation Architecture"></a>
</p>
<h2>
Overview video</h2>
<p>
<a href="proxy.php?url=https://www.youtube.com/watch?v=_m1BandnVsQ" rel="nofollow">
<img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--dpw0sr6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/pilotpirxie/recommendationimg/thumbnail.png" width="500" alt="Video">
</a>
</p>
<h2>
How it works</h2>
<h3>
How the data is stored:</h3>
<ul>
<li>Actors are stored in Redis as simple <code>String</code> keys with create date <code>timestamps</code> as value.</li>
<li>Items are <code>Set</code> type with <code>tags</code> as members. The item may have…</li>
</ul>
</div>
</div>
<div class="gh-btn-container"><a class="gh-btn" href="proxy.php?url=https://github.com/pilotpirxie/recommendation">View on GitHub</a></div>
</div>
<p>First of all, I set taxonomy for architecture. System is made of relations between four entities:</p>
<ul>
<li>Actor - decisive entity, for whom we try to match recommendations. In most cases this is a user or a group of users.</li>
<li>Item - this entity represents what we try to match e.g. product in a store, article on a blog or video on a streaming platform.</li>
<li>Event - are actor's actions used to calculate recommendation. It consist of tag with a score (weight).</li>
<li>Recommendation - final verdict, how close certain actor and item are.</li>
</ul>
<h1>
Redis
</h1>
<p>Having domain entities I tried many different Redis data structures to find one suitable to store them. To store actor data the most useful was HashSet with key of actorId, field of tag and value of score but I wanted to add event expiration and it isn't possible to do that easily with this structure. So instead I decided to use basic String structure where key contains all such information and value is the score. Then using SCAN with wildcard I'm retrieving data. Item have set of unique tags so the Set structure seems perfect choice and Actor - just to point existence - are again simple Strings with create timestamps.</p>
<h1>
Node
</h1>
<p>Node part of the application has been written using TypeScript and Express. System consists of app layer with recommendation mechanism run by controllers. Redis is hidden behind data access layer so can be easily replaced with different storage engine. High level architecture of recommendation system.</p>
<p><a href="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--yDKirvw2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6k7pwzxh74z23tnfkg9j.png" class="article-body-image-wrapper"><img src="proxy.php?url=https://res.cloudinary.com/practicaldev/image/fetch/s--yDKirvw2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6k7pwzxh74z23tnfkg9j.png" alt="Image description" width="621" height="922"></a></p>
<p>In the next part we are going look close at algorithm used to find recommendations.</p>
redishackathonwebdevalgorithmsjavascriptRecommendation system #2 - Business objectivesMeat BoyFri, 12 Aug 2022 21:58:00 +0000
https://dev.to/meatboy/writing-recommendation-system-1-business-objectives-35p3
https://dev.to/meatboy/writing-recommendation-system-1-business-objectives-35p3<p>In the previous post, I mentioned my plan to write a recommendation system using Redis and Nodejs. In this article, we look closer at the most important business objectives.</p>
<p>The recommendation system I'm creating will be used in the product-based application, similar to e-commerce apps. Will be difficult to measure direct leads as it's integrated with various partners and websites and it may vary from one to another. So recommendations will be calculated based on events with different weights. <br>
For now, I think about something like opening product page +1 score, give a like to product +2, comment +2, go to the details +5 and so on. For each tag associated with the product composite key with the event will be created.</p>
<p>Back to high-level requirements, the number of products will be relatively low when compared to full feature e-commerce and up to about ~10k items. Cold start which means a situation when the user didn't make any interaction before should be solved by choosing products popular among the overall audience of users. </p>
<p>The needs and tastes of the user may change so the composite of user-tag-event should expire, this can be done in Redis by setting TTL or in the more general database by WHERE clause plus maintenance worker or trigger for periodical cleanup.</p>
<p>In the next post, we will look more closely at the implementation. My initial thoughts are to use Redis TimeSeries to gather events and then use aggregation per composite for each user tag in a certain time span. However, it may be different as I need to dive deeper into Redis structures. If you have any advices or comments, you are welcome.</p>
webdevprogrammingalgorithmsredishackathonRecommendation system #1 - Redis HackathonMeat BoyFri, 05 Aug 2022 15:14:00 +0000
https://dev.to/meatboy/writing-recommendation-system-0-2lhh
https://dev.to/meatboy/writing-recommendation-system-0-2lhh<p>In one of the applications that I'm involved in on my spare time, with a friend we decided to add a recommendation section. With such section, users who interact with one product will get a recommendation of other similar products. I already read a little about this problem and seems to be not trivial. And because I like challenges decided to write my simple recommendation engine.</p>
<p>To make sure I won't discard this project too soon I decided to participate in <a href="proxy.php?url=https://dev.to/devteam/announcing-the-redis-hackathon-on-dev-3248">Redis Hackathon</a> not for prizes or splendour but to have fun with limitations and maybe cooperate with others thru post series. </p>
<p>My initial thoughts are to use Redis for the stream of user events and storage of products to match (eventually QuestDB but hey, it's Redis Hackathon!). Algorithms? Still researching, the easy one to implement seems to be the Jaccard index extended by weights on individual events. </p>
<p>If you are interested in this journey, follow me and in the next post, we are starting an adventure!</p>
webdevjavascriptnoderedishackathonWhat do you think about 4 hour workday?Meat BoyThu, 04 Aug 2022 12:49:11 +0000
https://dev.to/meatboy/what-do-you-think-about-4-hour-workday-4ppl
https://dev.to/meatboy/what-do-you-think-about-4-hour-workday-4ppl<p>As the civilization we have moved on with technology, education and overall life status. Sycophants praising honest toil seem to lose interest and more people are looking for leisure time. What is your opinion on 4 or 6 hour workday? </p>
discusscareerproductivityWhat is your goto technology for 2022? 🤔Meat BoyMon, 27 Jun 2022 07:53:51 +0000
https://dev.to/meatboy/what-is-your-goto-technology-for-2022-2gk4
https://dev.to/meatboy/what-is-your-goto-technology-for-2022-2gk4<p>It’s middle of 2022. Many technologies came up, many reached the enterprise level grade. What technology is your favourite? What technology are you eager to learn? What technology you are currently learning or see bright future for? </p>