This repository has been archived by the owner on Jun 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
data.json
1 lines (1 loc) · 233 KB
/
data.json
1
{"version":1,"blocks":[{"id":"61915a86-f40c-48ff-b06a-f2b2b7459db6","page-name":"The Big Hack","properties":{"public":true},"children":[{"id":"61915a86-1fa8-40ff-95fa-c2e91151043d","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-cd59-43cc-a822-500226d61365","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-2c89-42b9-b0cf-b208fad82f86","page-name":"Neovim","properties":{"public":true},"children":[{"id":"61915a86-5025-4498-bf8a-d7676ba1a2a4","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-63cb-4f31-96d4-c2c5093a736f","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"99dd926a-ffa9-4c4c-83b7-1eafa7643c29","page-name":"Favorites","children":[{"id":"61915a87-9721-4ba9-aa0a-728c1cba3690","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-2938-44fa-8bd0-91087a7dd1f0","page-name":"CSS","properties":{"public":true},"children":[{"id":"61915a86-a6bc-4868-90cf-8f1acacf2535","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-3e55-4379-bf64-4ffc6b6790d3","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-6f97-4ba3-828c-a4d5b8078f58","page-name":"Jest","properties":{"public":true},"children":[{"id":"61915a86-e5e8-4d22-b536-6919c423fe49","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-0df6-4bfd-b70f-5186c85305cf","format":"markdown","children":[],"title":[["Plain","Jest is a "],["Link",{"url":["Page_ref","JavaScript"],"label":[["Plain",""]],"full_text":"[[JavaScript]]","metadata":""}],["Plain"," testing framework."]],"body":[],"content":"Jest is a [[JavaScript]] testing framework."},{"id":"61915a86-14e8-41d3-9357-1220b59cbe3f","format":"markdown","children":[{"id":"61915a86-3849-4e4a-a31e-ec30a148072b","format":"markdown","children":[],"title":[["Plain","Interactive test runner"]],"body":[],"content":"Interactive test runner"}],"title":[["Emphasis",[["Bold"],[["Plain","Pros"]]]]],"body":[],"content":"**Pros**"},{"id":"61915a86-49a4-4238-8bee-b9413538f158","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"jestjs.io/"}],"label":[["Plain","https://jestjs.io/"]],"full_text":"https://jestjs.io/","metadata":""}]],"body":[],"content":"https://jestjs.io/"}]},{"id":"61915a86-2d17-47e6-82af-4d9ddb334585","page-name":"Mob programming","properties":{"public":true},"children":[{"id":"61915a86-f472-4aa7-a290-6474abc71636","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-e50e-4c21-92fd-b4e0aa6a6d2e","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-be71-47a4-8b34-efacad02c407","page-name":"Accessibility","children":[{"id":"61915a86-a1ff-4291-8a32-50e50acdcb25","format":"markdown","children":[],"title":[["Plain","Commonly abbreviated as "],["Emphasis",[["Bold"],[["Plain","a11y"]]]],["Plain"," (a numeronym) which means \"a - 11 letters - y\" as in \"a - ccessibilit - y\""]],"body":[],"content":"Commonly abbreviated as **a11y** (a numeronym) which means \"a - 11 letters - y\" as in \"a - ccessibilit - y\""}]},{"id":"61915a86-b011-4597-985e-a2c5e90a8291","page-name":"Testing","properties":{"public":true},"children":[{"id":"61915a86-5971-4244-910e-2c8468555d07","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-817d-4bbf-95f1-72a926fe2103","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-0b71-41c2-bf83-2f21fb0a3431","page-name":"2015-04-30","properties":{"public":true},"children":[{"id":"61915a86-c988-48a6-b7d2-a2d51f29f1e7","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-f7e5-45e7-a4c3-1923f3bdadcc","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-e43c-42c8-b665-bb2274a96b79","page-name":"Derek Prior","properties":{"public":true},"children":[{"id":"61915a86-9970-439e-9bee-c897ee6ee356","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-fa15-42d9-a769-2fcddbb0047c","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-dd4d-4528-80d3-360c4ada3505","page-name":"Always use real variable names in examples","properties":{"tags":["Development"],"pid":210426074810},"children":[{"id":"61915b2a-7d16-4790-a588-7c054981dcef","properties":{"tags":["Development"],"pid":210426074810},"format":"markdown","children":[],"content":"tags:: Development,\npid:: 210426074810"},{"id":"61915a86-d9ef-481c-802c-3379ee16706d","properties":{},"format":"markdown","children":[],"title":[["Plain","Just like you wouldn't use "],["Code","foo"],["Plain",", "],["Code","bar"],["Plain",", and "],["Code","baz"],["Plain"," in the real code you are writing, you should not use them when writing example code either."]],"body":[],"content":"Just like you wouldn't use `foo`, `bar`, and `baz` in the real code you are writing, you should not use them when writing example code either."},{"id":"61915a86-4603-4618-8a32-9fda9625c85f","format":"markdown","children":[],"title":[["Plain","Instead use real variable names that describe what it contains and create examples based on reality. This will make your examples easier to grasp and build upon."]],"body":[],"content":"Instead use real variable names that describe what it contains and create examples based on reality. This will make your examples easier to grasp and build upon."},{"id":"61915a86-b25a-4c20-9486-c5bc6a6f1070","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-d799-4f0d-9f6c-43b3804bd80b","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Jason Etcovich"],"label":[["Plain",""]],"full_text":"[[Jason Etcovich]]","metadata":""}],["Plain"," ("],["Link",{"url":["Page_ref","2020-08-24"],"label":[["Plain",""]],"full_text":"[[2020-08-24]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"Assorted thoughts on documentation\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"jasonet.co/posts/thoughts-on-docs/"}],"label":[["Plain","Link"]],"full_text":"[Link](https://jasonet.co/posts/thoughts-on-docs/)","metadata":""}]],"body":[],"content":"[[Jason Etcovich]] ([[2020-08-24]]). _\"Assorted thoughts on documentation\"_. [Link](https://jasonet.co/posts/thoughts-on-docs/)"}]},{"id":"61915a86-bc6b-4d58-b691-a76756cf3261","page-name":"Socratic method","properties":{"public":true},"children":[{"id":"61915a86-f410-4d23-9028-d395b5369dc0","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-0637-4373-8016-fa5793e2b377","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-ea3e-441e-8d8e-3cff6fbe5636","page-name":"Learning in public","properties":{"tags":["Learning"],"pid":210611104738},"children":[{"id":"61915a86-415b-4f45-9711-988901b2653c","properties":{"tags":["Learning"],"pid":210611104738},"format":"markdown","children":[],"content":"tags:: Learning,\npid:: 210611104738"},{"id":"61915a86-54d1-42d8-8df6-b6d1a0f58695","format":"markdown","children":[],"title":[["Plain","Share your knowledge and insights. To do this in the most effective way you'll need to "],["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}],["Plain",". This \"forces\" you to refine your thinking until you can explain the topic in the most accessible way."]],"body":[],"content":"Share your knowledge and insights. To do this in the most effective way you'll need to [[Explain in plain words]]. This \"forces\" you to refine your thinking until you can explain the topic in the most accessible way."},{"id":"61915a86-2793-419f-b457-9c047332740b","format":"markdown","children":[],"title":[["Plain","By learning and building in public you'll sooner or later post something that resonates with someone else. This feedback might lead to new insights and even better knowledge."]],"body":[],"content":"By learning and building in public you'll sooner or later post something that resonates with someone else. This feedback might lead to new insights and even better knowledge."}]},{"id":"61915a86-f80b-4406-be42-088e3fe74093","page-name":"Learning","properties":{"public":true},"children":[{"id":"61915a86-9d36-4ee6-aa0c-c4a9ac650731","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-3307-49e5-8c82-59ce3c5c1bbd","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-5d61-4ac9-b440-d4af59ab729f","page-name":"Rubocop","properties":{"public":true},"children":[{"id":"61915a86-d2fd-40b0-832c-8139abfa70c3","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-f6e7-496e-acec-f7a1dfb9a823","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-4426-4836-beb3-142a298aabea","page-name":"TIL","properties":{"public":true},"children":[{"id":"61915a86-4b8f-4757-9229-5cf0ce8415a6","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-e700-42ae-926f-6c9ad64fd4c7","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-46da-438b-93e2-9611f11d6f2c","page-name":"Max Rozen","properties":{"public":true},"children":[{"id":"61915a86-d54a-4fd0-8023-9c725334e400","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-6773-434a-96ea-c6c110a6f475","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/RozenMD"}],"label":[["Plain","Twitter"]],"full_text":"[Twitter](https://twitter.com/RozenMD)","metadata":""}]],"body":[],"content":"[Twitter](https://twitter.com/RozenMD)"}]},{"id":"61915a86-340c-496a-b0e7-9826b4e8f9a8","page-name":"Git","properties":{"public":true},"children":[{"id":"61915a86-d7d3-4429-a1c1-cd75554dc93f","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-9c55-4bb8-88cc-c688bd8b0b77","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-d361-4c44-9769-a72eeddb07f7","page-name":"2021-08-03","children":[{"id":"61915a86-9830-4752-912d-03a4b67d9981","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Write great alt texts for images"],"label":[["Plain",""]],"full_text":"[[Write great alt texts for images]]","metadata":""}]],"body":[],"content":"[[Write great alt texts for images]]"}]},{"id":"61915a86-9cab-451a-985d-c0910f6a5412","page-name":"2019-10-07","properties":{"public":true},"children":[{"id":"61915a86-4da4-4f53-b533-d1d434236d7b","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-e7b0-4225-864e-a3c50f159cec","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-61be-4ef7-9d39-f19fb3b46dd8","page-name":"Meta viewport for mobile devices","properties":{"public":true},"children":[{"id":"61915a86-98a5-4f02-b42e-242020f40ffe","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-88e1-46ba-99fd-39e3fc00abd6","format":"markdown","children":[],"title":[["Plain","Mobile devices render pages in a virtual viewport, which is usually wider than the screen, and shrink the content to fit. This viewport won't work when we want to use "],["Link",{"url":["Page_ref","Media queries"],"label":[["Plain",""]],"full_text":"[[Media queries]]","metadata":""}],["Plain",". If the viewport is "],["Code","980px"],["Plain"," and we have media queries that target "],["Code","480px"],["Plain",", they'll never fire."]],"body":[],"content":"Mobile devices render pages in a virtual viewport, which is usually wider than the screen, and shrink the content to fit. This viewport won't work when we want to use [[Media queries]]. If the viewport is `980px` and we have media queries that target `480px`, they'll never fire."},{"id":"61915a86-66be-41c8-8f8f-fecf4b535e78","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Apple"],"label":[["Plain",""]],"full_text":"[[Apple]]","metadata":""}],["Plain"," introduced the "],["Code","viewport"],["Plain"," "],["Code","meta"],["Plain"," tag in "],["Link",{"url":["Page_ref","Safari"],"label":[["Plain",""]],"full_text":"[[Safari]]","metadata":""}],["Plain"," to let developers control the viewport's size and scale. This is not part of any web standard, but it's supported by most other mobile browsers."]],"body":[],"content":"[[Apple]] introduced the `viewport` `meta` tag in [[Safari]] to let developers control the viewport's size and scale. This is not part of any web standard, but it's supported by most other mobile browsers."},{"id":"61915a86-6e7b-4ace-9b4e-9298aa598912","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">","\n"],"language":"html","pos_meta":{"start_pos":517,"end_pos":590},"full_content":"```html\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n```"}]],"content":" ```html\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n```"}]},{"id":"61915a86-0d23-46b8-9435-4d363186dceb","page-name":"IDE","properties":{"public":true},"children":[{"id":"61915a86-5c2f-4bd0-bbd6-65cc9f8662fe","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-d0e9-4ce1-958e-b6ac0f4fe5f6","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-b45f-4abf-a66b-549f327e7646","page-name":"Richard Feynman","properties":{"public":true},"children":[{"id":"61915a86-20f1-4bd1-8b0f-e14b5f841533","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-edf9-4cae-b4aa-641b305d895e","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-f663-41f6-b03e-379827cbc324","page-name":"SHA","children":[{"id":"61915a86-3f64-4dc5-9cd4-32dcccf33c5f","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-465a-4981-9701-a091fb2a941a","page-name":"2020-08-24","properties":{"public":true},"children":[{"id":"61915a86-4e44-42dd-900d-47b5a30b59f0","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-76b8-4514-969f-226fd24fdabc","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61968e02-801a-4607-ba58-344e39315c38","page-name":"2021-11-17","children":[{"id":"61968e02-cea3-4449-b556-f7a01dabcff3","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Use the object's identifier type"],"label":[["Plain",""]],"full_text":"[[Use the object's identifier type]]","metadata":""}]],"body":[],"content":"[[Use the object's identifier type]]"}]},{"id":"61915a86-7537-4293-9f88-0a6c0b128f2d","page-name":"2021-06-15","children":[{"id":"61915a86-d410-4518-9e7b-8d75796b0194","format":"markdown","children":[{"id":"61915a86-ed24-4965-82b0-d05a99313228","format":"markdown","children":[],"title":[["Plain","A great way of finding out whether an array method is mutating or not is by using "],["Link",{"url":["Complex",{"protocol":"https","link":"doesitmutate.xyz/"}],"label":[["Plain","https://doesitmutate.xyz/"]],"full_text":"https://doesitmutate.xyz/","metadata":""}]],"body":[],"content":"A great way of finding out whether an array method is mutating or not is by using https://doesitmutate.xyz/"},{"id":"61915a86-a07b-458c-a7c3-b925ebc7d5fe","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// React app","\n","\t ","\n","const data = [{ name: 'Test Testsson' }, { name: 'Aaron Aaronson' }];","\n","\t ","\n","// Incorrect","\n","// The sorting operation that was used didn't really work as expected","\n","// and since the sort method is mutating the original data","\n","// we got some unexpected results","\n","data.sort((a, b) => a.name > b.name).map((user) => <div>{user.name}</div>);","\n","\t ","\n","// Correct","\n","// Use the slice method to create a copy of the array","\n","// to not mutate the original data.","\n","// Update the sorting operation to use localeCompare for better results","\n","data","\n"," .slice()","\n"," .sort((a, b) => a.name.localeCompare(b.name))","\n"," .map((user) => <div>{user.name}</div>);","\n"],"language":"js","pos_meta":{"start_pos":511,"end_pos":1185},"full_content":"```js\n// React app\n\nconst data = [{ name: 'Test Testsson' }, { name: 'Aaron Aaronson' }];\n\n// Incorrect\n// The sorting operation that was used didn't really work as expected\n// and since the sort method is mutating the original data\n// we got some unexpected results\ndata.sort((a, b) => a.name > b.name).map((user) => <div>{user.name}</div>);\n\n// Correct\n// Use the slice method to create a copy of the array\n// to not mutate the original data.\n// Update the sorting operation to use localeCompare for better results\ndata\n .slice()\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((user) => <div>{user.name}</div>);\n```"}]],"content":"\t ```js\n// React app\n\nconst data = [{ name: 'Test Testsson' }, { name: 'Aaron Aaronson' }];\n\n// Incorrect\n// The sorting operation that was used didn't really work as expected\n// and since the sort method is mutating the original data\n// we got some unexpected results\ndata.sort((a, b) => a.name > b.name).map((user) => <div>{user.name}</div>);\n\n// Correct\n// Use the slice method to create a copy of the array\n// to not mutate the original data.\n// Update the sorting operation to use localeCompare for better results\ndata\n .slice()\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((user) => <div>{user.name}</div>);\n```"}],"title":[["Plain","Here's an example of a bug I found recently. It was a list of users that occasionally displayed the wrong name with the wrong image. The data was stored as a JSON file and was using a "],["Code",".sort()"],["Plain"," operation before looping over each item. "],["Code",".sort()"],["Plain"," is a "],["Emphasis",[["Bold"],[["Plain","mutating"]]]],["Plain"," method and by adding a "],["Code",".slice()"],["Plain"," before sorting we can create a shallow copy of the array to not alter the original data."]],"body":[],"content":"Here's an example of a bug I found recently. It was a list of users that occasionally displayed the wrong name with the wrong image. The data was stored as a JSON file and was using a `.sort()` operation before looping over each item. `.sort()` is a **mutating** method and by adding a `.slice()` before sorting we can create a shallow copy of the array to not alter the original data."}]},{"id":"61929dbc-f4cf-4ecb-a340-752ca4018b68","page-name":"Recommended way of importing React","properties":{"tags":["Development","React"],"pid":211115185038},"children":[{"id":"61929de2-73ba-4163-aef8-198d19f8191f","properties":{"tags":["Development","React"],"pid":211115185038},"format":"markdown","children":[],"content":"tags:: Development, React,\npid:: 211115185038\n"},{"id":"61929def-4ffc-47de-81c8-3998e1683830","properties":{},"format":"markdown","children":[],"title":[["Plain","There are a bunch of ways to import "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain",". Below are all the valid formats of importing "],["Code","useState"],["Plain"," from React. They have all been used at different times throughout the history of React. Read "],["Link",{"url":["Page_ref","Kent C. Dodds"],"label":[["Plain",""]],"full_text":"[[Kent C. Dodds]]","metadata":""}],["Plain","'s blog post below if you want to read a great summary of the differences."]],"body":[],"content":"There are a bunch of ways to import [[React]]. Below are all the valid formats of importing `useState` from React. They have all been used at different times throughout the history of React. Read [[Kent C. Dodds]]'s blog post below if you want to read a great summary of the differences."},{"id":"61929e63-0d11-491d-bcaf-83cd8c6b31bf","properties":{},"format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// global","\n","window.React.useState()","\n","\n","// CommonJS","\n","const React = require('react')","\n","React.useState()","\n","\n","// ESModules default import","\n","import React from 'react'","\n","React.useState()","\n","\n","// ESModules named import","\n","import { useState } from 'react'","\n","useState()","\n","\n","// ESModules namespace import","\n","import * as React from 'react'","\n","React.useState()","\n"],"language":"js","pos_meta":{"start_pos":8,"end_pos":325},"full_content":"```js\n// global\nwindow.React.useState()\n\n// CommonJS\nconst React = require('react')\nReact.useState()\n\n// ESModules default import\nimport React from 'react'\nReact.useState()\n\n// ESModules named import\nimport { useState } from 'react'\nuseState()\n\n// ESModules namespace import\nimport * as React from 'react'\nReact.useState()\n```"}]],"content":"```js\n// global\nwindow.React.useState()\n\n// CommonJS\nconst React = require('react')\nReact.useState()\n\n// ESModules default import\nimport React from 'react'\nReact.useState()\n\n// ESModules named import\nimport { useState } from 'react'\nuseState()\n\n// ESModules namespace import\nimport * as React from 'react'\nReact.useState()\n```"},{"id":"6192a02d-215a-48fb-8da1-ffb65a7cdd7d","properties":{},"format":"markdown","children":[],"title":[["Plain","Since React 17 was released we don't need to import React explicitly because of the new "],["Link",{"url":["Page_ref","JSX"],"label":[["Plain",""]],"full_text":"[[JSX]]","metadata":""}],["Plain"," transform. This means that only the final two formats above are needed today."]],"body":[],"content":"Since React 17 was released we don't need to import React explicitly because of the new [[JSX]] transform. This means that only the final two formats above are needed today."},{"id":"6192a138-6070-4b6e-ae84-d26ec590d54e","properties":{},"format":"markdown","children":[{"id":"6192a15e-b352-4db9-b0a1-88b92ec06640","properties":{},"format":"markdown","children":[],"title":[["Plain","No need to update the import every time we need something else, like "],["Code","useEffect"],["Plain"," or "],["Code","useReducer"],["Plain","."]],"body":[],"content":"No need to update the import every time we need something else, like ``useEffect`` or ``useReducer``."},{"id":"6192a179-02ba-4010-b8a9-24fc6c56e728","properties":{},"format":"markdown","children":[{"id":"6192a1d2-0425-422e-8356-56529e38a5ea","properties":{},"format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["import * as React from 'react'","\n","import Auth from './auth'","\n","\n","React.useState()","\n","Auth.useState()","\n"],"language":"js","pos_meta":{"start_pos":8,"end_pos":99},"full_content":"```js\nimport * as React from 'react'\nimport Auth from './auth'\n\nReact.useState()\nAuth.useState()\n```"}]],"content":"```js\nimport * as React from 'react'\nimport Auth from './auth'\n\nReact.useState()\nAuth.useState()\n```"}],"title":[["Plain","Namespaced versions of the hooks are immediately obvious where they came from. Maybe you are also importing a custom "],["Code","useState"],["Plain"," hook. Down the line it will be easier to maintain because you don't need to look up which of the hooks you have imported."]],"body":[],"content":"Namespaced versions of the hooks are immediately obvious where they came from. Maybe you are also importing a custom ``useState`` hook. Down the line it will be easier to maintain because you don't need to look up which of the hooks you have imported."}],"title":[["Plain","I would recommend using the last format, the namespaced import, with some of the benefits being"]],"body":[],"content":"I would recommend using the last format, the namespaced import, with some of the benefits being"},{"id":"6192a2d8-7caf-4e0d-a907-299e248ee34a","properties":{},"format":"markdown","children":[],"title":[["Plain","To make it easier to type I would recommend adding a snippet for it in your "],["Link",{"url":["Page_ref","IDE"],"label":[["Plain",""]],"full_text":"[[IDE]]","metadata":""}],["Plain",". Here's "],["Link",{"url":["Complex",{"protocol":"https","link":"snippets.willcodefor.beer/javascript/imra"}],"label":[["Plain","my snippet"]],"full_text":"[my snippet](https://snippets.willcodefor.beer/javascript/imra)","metadata":""}],["Plain"," which you can copy to "],["Link",{"url":["Page_ref","Ultisnips"],"label":[["Plain",""]],"full_text":"[[Ultisnips]]","metadata":""}],["Plain"," or "],["Link",{"url":["Page_ref","VS Code"],"label":[["Plain",""]],"full_text":"[[VS Code]]","metadata":""}],["Plain","."]],"body":[],"content":"To make it easier to type I would recommend adding a snippet for it in your [[IDE]]. Here's [my snippet](https://snippets.willcodefor.beer/javascript/imra) which you can copy to [[Ultisnips]] or [[VS Code]]."},{"id":"61929dc4-c063-41fa-8984-51aa6aa079b1","properties":{},"format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":"---"},{"id":"61929dc6-c8ec-46eb-8076-29dd2a0c0ea7","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Kent C. Dodds"],"label":[["Plain",""]],"full_text":"[[Kent C. Dodds]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","Importing React Through the Ages"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"epicreact.dev/importing-react-through-the-ages/"}],"label":[["Plain","Link"]],"full_text":"[Link](https://epicreact.dev/importing-react-through-the-ages/)","metadata":""}]],"body":[],"content":"[[Kent C. Dodds]]. _Importing React Through the Ages_. [Link](https://epicreact.dev/importing-react-through-the-ages/)"},{"id":"61929fb6-96be-4eb3-ba10-cb6497cbf311","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2020-02-22"],"label":[["Plain",""]],"full_text":"[[2020-02-22]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","The React team's recommendation"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/facebook/react/pull/18102"}],"label":[["Plain","Link"]],"full_text":"[Link](https://github.com/facebook/react/pull/18102)","metadata":""}]],"body":[],"content":"[[React]]. [[2020-02-22]]. _The React team's recommendation_. [Link](https://github.com/facebook/react/pull/18102)"},{"id":"61929ff6-2a1d-41ce-ba64-78fb0eec75b6","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Michael Jackson"],"label":[["Plain",""]],"full_text":"[[Michael Jackson]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-02"],"label":[["Plain",""]],"full_text":"[[2021-11-02]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/mjackson/status/1455320815361167362"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/mjackson/status/1455320815361167362)","metadata":""}]],"body":[],"content":"[[Michael Jackson]]. [[2021-11-02]]. [Tweet](https://twitter.com/mjackson/status/1455320815361167362)"},{"id":"6192a0bd-18a6-4008-a883-d82ed6e5e3bf","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Dan Abramov"],"label":[["Plain",""]],"full_text":"[[Dan Abramov]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2020-09-23"],"label":[["Plain",""]],"full_text":"[[2020-09-23]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/dan_abramov/status/1308739731551858689"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/dan_abramov/status/1308739731551858689)","metadata":""}]],"body":[],"content":"[[Dan Abramov]]. [[2020-09-23]]. [Tweet](https://twitter.com/dan_abramov/status/1308739731551858689)"}]},{"id":"61915a86-017a-4198-9f55-a2d9c4743377","page-name":"Implementing a strong code-review culture","properties":{"tags":["Code review"],"pid":210616101755},"children":[{"id":"61915bdd-9920-48f5-9ffb-ce1db11b3374","properties":{"tags":["Code review"],"pid":210616101755},"format":"markdown","children":[],"content":"tags:: Code review,\npid:: 210616101755"},{"id":"61915a86-a76a-4462-93aa-90f73603a18a","properties":{},"format":"markdown","children":[],"title":[["Plain","Code reviews are more about transferring knowledge inside a team and coming up with alternate solutions than finding bugs in the code. A strong code review culture will give us better code and better developers."]],"body":[],"content":"Code reviews are more about transferring knowledge inside a team and coming up with alternate solutions than finding bugs in the code. A strong code review culture will give us better code and better developers."},{"id":"61915a86-c2d9-4638-bb07-aebe5d541300","format":"markdown","children":[],"title":[["Plain","The "],["Emphasis",[["Bold"],[["Plain","why"]]]],["Plain"," is more important than the "],["Emphasis",[["Bold"],[["Plain","how"]]]],["Plain",". Take the time to write a thorough "],["Link",{"url":["Page_ref","PR"],"label":[["Plain",""]],"full_text":"[[PR]]","metadata":""}],["Plain"," description that explains the code change. Include documentation and links if they are relevant. You might not stay at the company forever and if you leave the context of the PR leaves with you. If you do stick around, your future self will thank you."]],"body":[],"content":"The **why** is more important than the **how**. Take the time to write a thorough [[PR]] description that explains the code change. Include documentation and links if they are relevant. You might not stay at the company forever and if you leave the context of the PR leaves with you. If you do stick around, your future self will thank you."},{"id":"61915a86-b1e9-4ea7-92c5-18618b4d7710","format":"markdown","children":[],"title":[["Plain","Written communication can often be perceived as negative. Review what you've written before publishing. Try to read it as the the one who will receive the text and try to make it feel as positive as possible. Use the "],["Link",{"url":["Page_ref","Socratic method"],"label":[["Plain",""]],"full_text":"[[Socratic method]]","metadata":""}]],"body":[],"content":"Written communication can often be perceived as negative. Review what you've written before publishing. Try to read it as the the one who will receive the text and try to make it feel as positive as possible. Use the [[Socratic method]]"},{"id":"61915a86-fc3a-4131-ba42-4c3183672ed2","format":"markdown","children":[{"id":"61915a86-83e0-4840-92a8-6517c5c0dced","format":"markdown","children":[],"title":[["Plain","\"Extract this to a service\" -> \"What do you think about extracting this to a service?\""]],"body":[],"content":"\"Extract this to a service\" -> \"What do you think about extracting this to a service?\""}],"title":[["Plain","The "],["Link",{"url":["Page_ref","PR"],"label":[["Plain",""]],"full_text":"[[PR]]","metadata":""}],["Plain"," is a discussion. "],["Emphasis",[["Bold"],[["Plain","Don't tell the author to do something, ask them about it."]]]]],"body":[],"content":"The [[PR]] is a discussion. **Don't tell the author to do something, ask them about it.**"},{"id":"61915a86-a64c-44a7-860f-768dddc3b95b","format":"markdown","children":[],"title":[["Plain","Conflicts will arise and are not necessarily a bad thing. If we don't agree, be open to discussing the issues and the process."]],"body":[],"content":"Conflicts will arise and are not necessarily a bad thing. If we don't agree, be open to discussing the issues and the process."},{"id":"61915a86-051f-4241-a915-fff2f8644f8f","format":"markdown","children":[{"id":"61915a86-bacf-456a-8732-78592f2990ac","format":"markdown","children":[{"id":"61915a86-b531-46d9-a437-aa3d72ed9d05","format":"markdown","children":[],"title":[],"body":[["Quote",[["Paragraph",[["Plain","Naming is hard. Renaming is "],["Emphasis",[["Bold"],[["Plain","harder"]]]],["Plain",". Spend the time up front. - "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/laurieontech/status/1402313492162613252"}],"label":[["Plain","@laurieontech"]],"full_text":"[@laurieontech](https://twitter.com/laurieontech/status/1402313492162613252)","metadata":""}],["Break_Line"]]]]]],"content":"\t\t > Naming is hard. Renaming is **harder**. Spend the time up front. - [@laurieontech](https://twitter.com/laurieontech/status/1402313492162613252)"}],"title":[["Plain","Think about naming."]],"body":[],"content":"Think about naming."},{"id":"61915a86-6156-438d-a0f4-466dff01483e","format":"markdown","children":[],"title":[["Plain","Review the complexity and make suggestions for possible improvements."]],"body":[],"content":"Review the complexity and make suggestions for possible improvements."},{"id":"61915a86-b101-460b-86e5-4b611d8061aa","format":"markdown","children":[],"title":[["Plain","Check on test coverage. 100% coverage isn't absolutely necessary, but make sure that we've added tests for the important paths."]],"body":[],"content":"Check on test coverage. 100% coverage isn't absolutely necessary, but make sure that we've added tests for the important paths."}],"title":[["Plain","What to review"]],"body":[],"content":"What to review"},{"id":"61915a86-76aa-414e-9c25-20742155b0cb","format":"markdown","children":[],"title":[["Plain","Styling is important, but it should, if possible, be solved using automation. Use "],["Link",{"url":["Page_ref","Rubocop"],"label":[["Plain",""]],"full_text":"[[Rubocop]]","metadata":""}],["Plain",", "],["Link",{"url":["Page_ref","ESLint"],"label":[["Plain",""]],"full_text":"[[ESLint]]","metadata":""}],["Plain",", "],["Link",{"url":["Page_ref","Prettier"],"label":[["Plain",""]],"full_text":"[[Prettier]]","metadata":""}],["Plain"," etc."]],"body":[],"content":"Styling is important, but it should, if possible, be solved using automation. Use [[Rubocop]], [[ESLint]], [[Prettier]] etc."},{"id":"61915a86-89ab-4b8c-91ea-1927adfb2393","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-4361-4788-b101-4b0de10f1b97","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Derek Prior"],"label":[["Plain",""]],"full_text":"[[Derek Prior]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2015-04-30"],"label":[["Plain",""]],"full_text":"[[2015-04-30]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","RailsConf 2015 - Implementing a Strong Code-Review Culture"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"www.youtube.com/watch?v=PJjmw9TRB7s"}],"label":[["Plain","Link"]],"full_text":"[Link](https://www.youtube.com/watch?v=PJjmw9TRB7s)","metadata":""}]],"body":[],"content":"[[Derek Prior]]. ([[2015-04-30]]). _RailsConf 2015 - Implementing a Strong Code-Review Culture_. [Link](https://www.youtube.com/watch?v=PJjmw9TRB7s)"}]},{"id":"61915a86-dc72-49d2-8d86-537bbd1669fd","page-name":"CSS Grid tricks","properties":{"public":true},"children":[{"id":"61915a86-a865-4c72-a95b-7fd0c9b27a02","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-5fe6-4e75-8b9d-bac9dfdb5287","format":"markdown","children":[{"id":"61915a86-934b-4691-8e18-8517b884e3db","format":"markdown","children":[],"title":[["Plain","We have some content that we want to position in the center of the screen. For this we can use "],["Link",{"url":["Page_ref","CSS Grid"],"label":[["Plain",""]],"full_text":"[[CSS Grid]]","metadata":""}],["Plain",". By defining fixed values at the edges of our grid template we can achieve spacing without using "],["Code","padding"],["Plain"," when the grid resizes on a smaller screen."]],"body":[],"content":"We have some content that we want to position in the center of the screen. For this we can use [[CSS Grid]]. By defining fixed values at the edges of our grid template we can achieve spacing without using `padding` when the grid resizes on a smaller screen."},{"id":"61915a86-2368-4ea4-8608-689b95eef5f9","format":"markdown","children":[],"title":[["Plain","Remember to add "],["Link",{"url":["Page_ref","Meta viewport for mobile devices"],"label":[["Plain",""]],"full_text":"[[Meta viewport for mobile devices]]","metadata":""}],["Plain",", otherwise the content won't scale correctly on smaller screens and the spacings will not work."]],"body":[],"content":"Remember to add [[Meta viewport for mobile devices]], otherwise the content won't scale correctly on smaller screens and the spacings will not work."},{"id":"61915a86-6e41-4486-8394-bda6e408d48f","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["<div class=\"grid\">","\n","\t<div class=\"content\">","\n"," Elit suscipit consequuntur rerum alias eius. Autem soluta voluptas","\n"," doloremque corrupti distinctio dicta Cumque sit accusamus minima magni","\n"," voluptatum. Distinctio veritatis consectetur et eligendi dolores est","\n"," Impedit at tenetur pariatur","\n","\t</div>","\n","</div>","\n","\t ","\n"],"language":"html","pos_meta":{"start_pos":482,"end_pos":829},"full_content":"```html\n<div class=\"grid\">\n\t<div class=\"content\">\n Elit suscipit consequuntur rerum alias eius. Autem soluta voluptas\n doloremque corrupti distinctio dicta Cumque sit accusamus minima magni\n voluptatum. Distinctio veritatis consectetur et eligendi dolores est\n Impedit at tenetur pariatur\n\t</div>\n</div>\n\n```"}]],"content":"\t ```html\n<div class=\"grid\">\n\t<div class=\"content\">\n Elit suscipit consequuntur rerum alias eius. Autem soluta voluptas\n doloremque corrupti distinctio dicta Cumque sit accusamus minima magni\n voluptatum. Distinctio veritatis consectetur et eligendi dolores est\n Impedit at tenetur pariatur\n\t</div>\n</div>\n\n```"},{"id":"61915a86-0da6-42c2-a2a2-b778b5b2fc92","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":[".grid {","\n"," display: grid;","\n"," grid-template-columns: 20px 1fr minmax(0, 960px) 1fr 20px;","\n","}","\n","\t ","\n","/* From the image below we can see that our content's","\n"," area starts at column 3 and ends at column 4 */","\n",".content {","\n"," grid-column: 3 / 4;","\n"," /* This is a shorthand form of:","\n"," * grid-column-start: 3;","\n"," * grid-column-end: 4;","\n"," */","\n","}","\n"],"language":"css","pos_meta":{"start_pos":846,"end_pos":1286},"full_content":"```css\n .grid {\n display: grid;\n grid-template-columns: 20px 1fr minmax(0, 960px) 1fr 20px;\n }\n\n /* From the image below we can see that our content's\n area starts at column 3 and ends at column 4 */\n .content {\n grid-column: 3 / 4;\n /* This is a shorthand form of:\n * grid-column-start: 3;\n * grid-column-end: 4;\n */\n }\n```"}]],"content":"\t ```css\n .grid {\n display: grid;\n grid-template-columns: 20px 1fr minmax(0, 960px) 1fr 20px;\n }\n\n /* From the image below we can see that our content's\n area starts at column 3 and ends at column 4 */\n .content {\n grid-column: 3 / 4;\n /* This is a shorthand form of:\n * grid-column-start: 3;\n * grid-column-end: 4;\n */\n }\n```"},{"id":"61915a86-2e1c-4cc1-8a00-d0de956404e3","format":"markdown","children":[],"title":[["Plain","Here's the grid in desktop size with the grid columns highlighted using "],["Link",{"url":["Page_ref","Chrome"],"label":[["Plain",""]],"full_text":"[[Chrome]]","metadata":""}],["Plain","'s "],["Code","grid"],["Plain"," tool."]],"body":[],"content":"Here's the grid in desktop size with the grid columns highlighted using [[Chrome]]'s `grid` tool."},{"id":"61915a86-cdcf-44fb-a15e-0c3a9fb5f4ae","format":"markdown","children":[],"title":[["Link",{"url":["Search","../assets/grid_desktop_1630347066416_0.png"],"label":[["Plain","grid_desktop.png"]],"full_text":"![grid_desktop.png](../assets/grid_desktop_1630347066416_0.png)","metadata":""}]],"body":[],"content":"![grid_desktop.png](../assets/grid_desktop_1630347066416_0.png)"},{"id":"61915a86-8a4d-4452-af7b-8f37cc8ebdb8","format":"markdown","children":[],"title":[["Plain","The same grid on a screen size of "],["Code","411px"],["Plain"," (Pixel 2 XL) displays that our "],["Code","1fr"],["Plain"," columns are very small (or non-existent) at this point leaving only our \"padding\" columns and the content."]],"body":[],"content":"The same grid on a screen size of `411px` (Pixel 2 XL) displays that our `1fr` columns are very small (or non-existent) at this point leaving only our \"padding\" columns and the content."},{"id":"61915a86-5284-4c55-a059-dedb72e58815","format":"markdown","children":[],"title":[["Link",{"url":["Search","../assets/grid_mobile_1630347074383_0.png"],"label":[["Plain","grid_mobile.png"]],"full_text":"![grid_mobile.png](../assets/grid_mobile_1630347074383_0.png)","metadata":""}]],"body":[],"content":"![grid_mobile.png](../assets/grid_mobile_1630347074383_0.png)"}],"title":[["Emphasis",[["Bold"],[["Plain","Add columns for spacing on mobile"]]]]],"body":[],"content":"**Add columns for spacing on mobile**"}]},{"id":"61915a86-f1d0-4eb9-b30a-41794077a390","page-name":"Save disk space by deleting node_modules","properties":{"tags":["JavaScript"],"pid":211110190432},"children":[{"id":"61915a86-970b-4f71-bb50-dfb98f6c23f1","properties":{"tags":["JavaScript"],"pid":211110190432},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"tags:: JavaScript,\npid:: 211110190432\n\n"},{"id":"61915a86-8039-4f55-acff-15984e4eaa4b","format":"markdown","children":[],"title":[["Plain","After developing on a computer for a while you'll probably end up with a bunch of projects. If those projects are "],["Link",{"url":["Page_ref","JavaScript"],"label":[["Plain",""]],"full_text":"[[JavaScript]]","metadata":""}],["Plain"," there's a good change that they contain a "],["Code","node_modules"],["Plain"," directory. From time to time it's a good idea to remove all of these folders, since they can get quite big, and re-download the dependencies in the projects you're actively using."]],"body":[],"content":"After developing on a computer for a while you'll probably end up with a bunch of projects. If those projects are [[JavaScript]] there's a good change that they contain a ``node_modules`` directory. From time to time it's a good idea to remove all of these folders, since they can get quite big, and re-download the dependencies in the projects you're actively using."},{"id":"61915a86-3935-461a-81fb-47bbb0a59fb8","properties":{},"format":"markdown","children":[{"id":"61915a86-f388-48a3-afdb-1659f4e3b831","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["alias node-prune='find . -name \"node_modules\" -type d -prune -exec rm -rf '{}' +'","\n"],"language":"bash","pos_meta":{"start_pos":732,"end_pos":820},"full_content":"```bash\n\t alias node-prune='find . -name \"node_modules\" -type d -prune -exec rm -rf '{}' +'\n\t ```\n"}]],"content":"```bash\nalias node-prune='find . -name \"node_modules\" -type d -prune -exec rm -rf '{}' +'\n```"}],"title":[["Plain","I have aliased the following command to "],["Code","node-prune"],["Plain"," and have been "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/dotfiles/commit/a440d8abcdb47cf6fe5d9af69519f960f7c96ce0"}],"label":[["Plain","using it"]],"full_text":"[using it](https://github.com/believer/dotfiles/commit/a440d8abcdb47cf6fe5d9af69519f960f7c96ce0)","metadata":""}],["Plain"," since "],["Link",{"url":["Page_ref","2019-12-11"],"label":[["Plain",""]],"full_text":"[[2019-12-11]]","metadata":""}],["Plain"," without any issues. When I ran the command on "],["Link",{"url":["Page_ref","2021-11-08"],"label":[["Plain",""]],"full_text":"[[2021-11-08]]","metadata":""}],["Plain"," I got back ~40 GB of disk space. Use it "],["Emphasis",[["Bold"],[["Plain","at your own risk"]]]],["Plain","."]],"body":[],"content":"I have aliased the following command to ``node-prune`` and have been [using it](https://github.com/believer/dotfiles/commit/a440d8abcdb47cf6fe5d9af69519f960f7c96ce0) since [[2019-12-11]] without any issues. When I ran the command on [[2021-11-08]] I got back ~40 GB of disk space. Use it **at your own risk**."},{"id":"61915a86-88d7-48c8-b583-38e3c9de183a","format":"markdown","children":[{"id":"61915a86-7c76-4e24-a89d-aaebb6c0fa7a","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["find . -name \"node_modules\" -type d -prune -print | xargs du -chs","\n"],"language":"bash","pos_meta":{"start_pos":932,"end_pos":1004},"full_content":"```bash\n\t find . -name \"node_modules\" -type d -prune -print | xargs du -chs\n\t ```\n"}]],"content":"```bash\nfind . -name \"node_modules\" -type d -prune -print | xargs du -chs\n```"}],"title":[["Plain","If you just want to find and display the size of the folders you can use the following command"]],"body":[],"content":"If you just want to find and display the size of the folders you can use the following command"},{"id":"61915a86-2e57-465d-b37c-ae392598d604","format":"markdown","children":[],"title":[["Plain","There's also "],["Code","npkill"],["Plain"," which looks up and displays "],["Code","node_modules"],["Plain",", displays their size and allows you to delete the folders. Run it by using "],["Code","npx npkill"]],"body":[],"content":"There's also ``npkill`` which looks up and displays ``node_modules``, displays their size and allows you to delete the folders. Run it by using ``npx npkill``"},{"id":"61915a86-5896-4a22-b679-321ac212f614","format":"markdown","children":[],"title":[["Plain","I also posted this on "],["Link",{"url":["Complex",{"protocol":"https","link":"willcodefor.beer/posts/save-disk-space-by-deleting-node-modules/"}],"label":[["Plain","my blog"]],"full_text":"[my blog](https://willcodefor.beer/posts/save-disk-space-by-deleting-node-modules/)","metadata":""}],["Plain"," with explanations of the command."]],"body":[],"content":"I also posted this on [my blog](https://willcodefor.beer/posts/save-disk-space-by-deleting-node-modules/) with explanations of the command."},{"id":"61915a86-af56-4a7e-a794-c8473d602625","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-3a8a-460c-a20a-2a223c0be22c","format":"markdown","children":[{"id":"61915a86-d1d7-4c2a-b49a-ea700eb79568","format":"markdown","children":[],"title":[["Macro",{"name":"tweet","arguments":["https://twitter.com/erikras/status/1458074052929728515"]}]],"body":[],"content":"{{tweet https://twitter.com/erikras/status/1458074052929728515}}"}],"title":[["Link",{"url":["Page_ref","Erik Rasmussen"],"label":[["Plain",""]],"full_text":"[[Erik Rasmussen]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-09"],"label":[["Plain",""]],"full_text":"[[2021-11-09]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/erikras/status/1458074052929728515"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/erikras/status/1458074052929728515)","metadata":""}]],"body":[],"content":"[[Erik Rasmussen]]. [[2021-11-09]]. [Tweet](https://twitter.com/erikras/status/1458074052929728515)"}]},{"id":"61915a86-bb5b-4b51-83e0-28d3f4ff200c","page-name":"2021-06-21","children":[{"id":"61915a86-dea6-4158-a034-e347b529a523","format":"markdown","children":[],"title":[["Plain","I hadn't kept up with what the latest was in the newly announced "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," 18 but decided that it was the perfect thing to start this Monday off with. "],["Link",{"url":["Page_ref","What's new in React 18"],"label":[["Plain",""]],"full_text":"[[What's new in React 18]]","metadata":""}]],"body":[],"content":"I hadn't kept up with what the latest was in the newly announced [[React]] 18 but decided that it was the perfect thing to start this Monday off with. [[What's new in React 18]]"},{"id":"61915a86-36a4-4ff5-83e5-5790a2b3472e","format":"markdown","children":[{"id":"61915a86-5ca1-48ca-8c44-a53f34beb66a","format":"markdown","children":[],"title":[["Plain","Neither of the solutions affect the "],["Link",{"url":["Page_ref","Accessibility"],"label":[["Plain",""]],"full_text":"[[Accessibility]]","metadata":""}],["Plain"," on the page since pinch-to-zoom will still work."]],"body":[],"content":"Neither of the solutions affect the [[Accessibility]] on the page since pinch-to-zoom will still work."},{"id":"61915a86-dde2-4097-af6a-dd5a8259a132","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["/* Set the property on the entire page or on specific","\n","elements like a or button */","\n","html {","\n"," touch-action: manipulation;","\n","}","\n"],"language":"css","pos_meta":{"start_pos":616,"end_pos":757},"full_content":"``` css\n/* Set the property on the entire page or on specific\nelements like a or button */\nhtml {\n touch-action: manipulation;\n}\n```"}]],"content":"\t ``` css\n/* Set the property on the entire page or on specific\nelements like a or button */\nhtml {\n touch-action: manipulation;\n}\n```"}],"title":[["Plain","If you use a correct "],["Link",{"url":["Page_ref","Meta viewport for mobile devices"],"label":[["Plain",""]],"full_text":"[[Meta viewport for mobile devices]]","metadata":""}],["Plain"," you'll never see the 300-350 ms tap delay that browsers add to wait for a double tap. If you for some reason can't add the meta tag, there's also a "],["Link",{"url":["Page_ref","CSS"],"label":[["Plain",""]],"full_text":"[[CSS]]","metadata":""}],["Plain"," property that does the same thing. It's not supported by "],["Link",{"url":["Page_ref","Firefox"],"label":[["Plain",""]],"full_text":"[[Firefox]]","metadata":""}],["Plain",", so the meta tag is preferred."]],"body":[],"content":"If you use a correct [[Meta viewport for mobile devices]] you'll never see the 300-350 ms tap delay that browsers add to wait for a double tap. If you for some reason can't add the meta tag, there's also a [[CSS]] property that does the same thing. It's not supported by [[Firefox]], so the meta tag is preferred."}]},{"id":"61915a86-91c9-47b9-9a19-0a06efacea75","page-name":"Vim","properties":{"public":true},"children":[{"id":"61915a86-1f0b-4086-bd64-43a131106252","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-dbf7-4b9e-8b83-3af19e504a1d","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-f0c2-4efb-8b4e-2fa1759dc42a","page-name":"ESLint","properties":{"public":true},"children":[{"id":"61915a86-2e97-46a7-a123-b1cfec51c548","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-fd3d-4d62-9495-3c3c6c2421fa","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-c794-4fb6-a7fb-59a46b555cbc","page-name":"Teaching","properties":{"public":true},"children":[{"id":"61915a86-ecd5-4fa7-bafe-7958d611c3b9","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-fadc-4613-ad3c-55735c2c6b27","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-f7bd-4429-9ea8-4218d13343de","page-name":"Share shortcuts and plugins when teaching new developers","properties":{"tags":["Development","Teaching"],"pid":211001194321},"children":[{"id":"61915a86-f51b-4370-b7c7-dba1e1d43b3c","properties":{"tags":["Development","Teaching"],"pid":211001194321},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"tags:: Development, Teaching\npid:: 211001194321\n\n"},{"id":"61915a86-cf95-44a5-b8ba-4b3eb0e3882f","format":"markdown","children":[],"title":[["Plain","When teaching a new developer, share with them what keyboard shortcuts/commands you use and if you're using any specific plugins that can help with the task. These things are easy to forget the more advanced your own knowledge gets, but can have a great impact to new developers."]],"body":[],"content":"When teaching a new developer, share with them what keyboard shortcuts/commands you use and if you're using any specific plugins that can help with the task. These things are easy to forget the more advanced your own knowledge gets, but can have a great impact to new developers."},{"id":"61915a86-b00d-40f4-9b5a-3c24bf86a77e","format":"markdown","children":[],"title":[["Plain","This is closely related to "],["Link",{"url":["Page_ref","Describe what you're doing before doing it"],"label":[["Plain",""]],"full_text":"[[Describe what you're doing before doing it]]","metadata":""}]],"body":[],"content":"This is closely related to [[Describe what you're doing before doing it]]"},{"id":"61915a86-637d-4089-8662-b63adf1162fd","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-d0d7-4d84-8420-ebb03fbe79c4","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Emma Bostian"],"label":[["Plain",""]],"full_text":"[[Emma Bostian]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-09-28"],"label":[["Plain",""]],"full_text":"[[2021-09-28]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","Twitter"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/EmmaBostian/status/1442830478176923649"}],"label":[["Plain","Link"]],"full_text":"[Link](https://twitter.com/EmmaBostian/status/1442830478176923649)","metadata":""}]],"body":[],"content":"[[Emma Bostian]]. ([[2021-09-28]]). _Twitter_. [Link](https://twitter.com/EmmaBostian/status/1442830478176923649)"}]},{"id":"61915a86-031a-4e53-a4be-d4bb22a09fa3","page-name":"Difference between nullish coalescing (??) and logical or (||)","properties":{"title":"Difference between nullish coalescing (??) and logical or (||)","tags":["Development","JavaScript"],"pid":210922101321},"children":[{"id":"61915a86-f140-4087-8146-66fc8869279a","properties":{"title":"Difference between nullish coalescing (??) and logical or (||)","tags":["Development","JavaScript"],"pid":210922101321},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"title:: Difference between nullish coalescing (??) and logical or (||)\ntags:: Development, JavaScript\npid:: 210922101321\n\n"},{"id":"61915a86-8080-4d39-aa34-b0f697a343fd","format":"markdown","children":[],"title":[["Code","||"],["Plain"," (logical OR) will use the right value when the left side is "],["Link",{"url":["Page_ref","falsy"],"label":[["Plain",""]],"full_text":"[[falsy]]","metadata":""}],["Plain",". "],["Code","??"],["Plain"," (nullish coalescing) only uses the right value when the left side is "],["Emphasis",[["Italic"],[["Plain","nullish"]]]],["Plain",", i.e. "],["Code","null"],["Plain"," or "],["Code","undefined"],["Plain","."]],"body":[],"content":"`||` (logical OR) will use the right value when the left side is [[falsy]]. `??` (nullish coalescing) only uses the right value when the left side is _nullish_, i.e. `null` or `undefined`."},{"id":"61915a86-4e05-486a-87ab-1d22e098bece","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// ||","\n","console.log('' || 'default') // 'default'","\n","console.log('test' || 'default') // 'test'","\n","\n","console.log(0 || 'default') // 'default'","\n","console.log(12 || 'default') // 12","\n","\n","console.log(false || 'default') // 'default'","\n","console.log(true || 'default') // true","\n","\n","console.log(undefined || 'default') // 'default'","\n","console.log(null || 'default') // 'default'","\n","\n","// ??","\n","console.log('' ?? 'default') // ''","\n","console.log('test' ?? 'default') // 'test'","\n","\n","console.log(0 ?? 'default') // 0","\n","console.log(12 ?? 'default') // 12","\n","\n","console.log(false ?? 'default') // false","\n","console.log(true ?? 'default') // true","\n","\n","console.log(undefined ?? 'default') // 'default'","\n","console.log(null ?? 'default') // 'default'","\n"],"language":"js","pos_meta":{"start_pos":321,"end_pos":1035},"full_content":"```js\n // ||\n console.log('' || 'default') // 'default'\n console.log('test' || 'default') // 'test'\n\n console.log(0 || 'default') // 'default'\n console.log(12 || 'default') // 12\n\n console.log(false || 'default') // 'default'\n console.log(true || 'default') // true\n\n console.log(undefined || 'default') // 'default'\n console.log(null || 'default') // 'default'\n\n // ??\n console.log('' ?? 'default') // ''\n console.log('test' ?? 'default') // 'test'\n\n console.log(0 ?? 'default') // 0\n console.log(12 ?? 'default') // 12\n\n console.log(false ?? 'default') // false\n console.log(true ?? 'default') // true\n\n console.log(undefined ?? 'default') // 'default'\n console.log(null ?? 'default') // 'default'\n ```\n"}]],"content":"```js\n// ||\nconsole.log('' || 'default') // 'default'\nconsole.log('test' || 'default') // 'test'\n\nconsole.log(0 || 'default') // 'default'\nconsole.log(12 || 'default') // 12\n\nconsole.log(false || 'default') // 'default'\nconsole.log(true || 'default') // true\n\nconsole.log(undefined || 'default') // 'default'\nconsole.log(null || 'default') // 'default'\n\n// ??\nconsole.log('' ?? 'default') // ''\nconsole.log('test' ?? 'default') // 'test'\n\nconsole.log(0 ?? 'default') // 0\nconsole.log(12 ?? 'default') // 12\n\nconsole.log(false ?? 'default') // false\nconsole.log(true ?? 'default') // true\n\nconsole.log(undefined ?? 'default') // 'default'\nconsole.log(null ?? 'default') // 'default'\n```"}]},{"id":"61915a86-177a-4066-a5bd-d1b43bad63e2","page-name":"Johnny Ji","properties":{"public":true},"children":[{"id":"61915a86-9791-4719-a1ab-de86701a9240","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-b788-4f45-bd66-b9c1710f1066","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-7256-4ba6-815f-5686e77f67a1","page-name":"API","properties":{"public":true},"children":[{"id":"61915a86-4b07-43ec-8c92-dbba8d883058","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-0329-4358-956c-bdc9649b88ae","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61968d8c-7a64-4ec5-8b93-23ef1e9820d3","page-name":"TypeScript","properties":{"public":true},"children":[{"id":"61915a86-6f7e-4a00-b11b-7a50f861d865","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-cc31-45be-bd4e-ade7bd6b4a62","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-128d-4f05-8049-a9bf752a8de8","page-name":"2021-06-10","properties":{"public":true},"children":[{"id":"61915a86-e16f-4172-bb2c-76053574b43c","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-01f1-476b-9f27-30d54a2ac209","format":"markdown","children":[{"id":"61915a86-39de-47a0-a9a6-4bebfcff5c12","format":"markdown","children":[],"title":[["Plain","Since I always forget it I've created a snippet for it. Below is a version for "],["Link",{"url":["Page_ref","UltiSnips"],"label":[["Plain",""]],"full_text":"[[UltiSnips]]","metadata":""}],["Plain"," and it's also available as a "],["Link",{"url":["Page_ref","VS Code"],"label":[["Plain",""]],"full_text":"[[VS Code]]","metadata":""}],["Plain"," snippet "],["Link",{"url":["Complex",{"protocol":"https","link":"snippets.willcodefor.beer/html/metav"}],"label":[["Plain","on my snippets page"]],"full_text":"[on my snippets page](https://snippets.willcodefor.beer/html/metav)","metadata":""}],["Plain","."]],"body":[],"content":"Since I always forget it I've created a snippet for it. Below is a version for [[UltiSnips]] and it's also available as a [[VS Code]] snippet [on my snippets page](https://snippets.willcodefor.beer/html/metav)."},{"id":"61915a86-3d21-47e9-93d0-c3e1b9705bf5","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["# Make the viewport scale correctly on mobile devices","\n","snippet metav \"Meta viewport\"","\n","<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />","\n","endsnippet","\n"],"pos_meta":{"start_pos":401,"end_pos":582},"full_content":"```\n# Make the viewport scale correctly on mobile devices\nsnippet metav \"Meta viewport\"\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\nendsnippet\n```"}]],"content":"\t ```\n# Make the viewport scale correctly on mobile devices\nsnippet metav \"Meta viewport\"\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\nendsnippet\n```"}],"title":[["Plain","I'll keep this here for future reference when I eventually forget what the meta tag should be and have to look it up again "],["Link",{"url":["Page_ref","Meta viewport for mobile devices"],"label":[["Plain",""]],"full_text":"[[Meta viewport for mobile devices]]","metadata":""}]],"body":[],"content":"I'll keep this here for future reference when I eventually forget what the meta tag should be and have to look it up again [[Meta viewport for mobile devices]]"},{"id":"61915a86-3ca0-4518-9b4f-d7e6fe8e9f97","format":"markdown","children":[],"title":[["Plain","An example of how to use grid columns as \"padding\" "],["Link",{"url":["Page_ref","CSS Grid tricks"],"label":[["Plain",""]],"full_text":"[[CSS Grid tricks]]","metadata":""}]],"body":[],"content":"An example of how to use grid columns as \"padding\" [[CSS Grid tricks]]"}]},{"id":"61915a86-5d51-4cda-8b9b-06e3afc8511f","page-name":"Shu Omi","properties":{"public":true},"children":[{"id":"61915a86-b58c-413b-bcdf-a64568f48472","properties":{"public":true},"format":"markdown","children":[],"content":"public:: true\n"}]},{"id":"61915a86-1143-417a-94de-1600f674785c","page-name":"Braden Becker","properties":{"public":true},"children":[{"id":"61915a86-5c0f-4817-be43-cb72fa4594b4","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-6347-4b6c-bba4-9bae281605eb","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-fe13-4b4f-bddd-5aa3fa093bf6","page-name":"How to save and quit Vim","properties":{"title":"How to save and quit Vim","public":true},"children":[{"id":"61915a86-65d4-4ea4-ad79-229c9584cfde","properties":{"title":"How to save and quit Vim","public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"title:: How to save and quit Vim\npublic:: true\n\n"},{"id":"61915a86-46e4-4750-b8d4-9c3f61581e09","format":"markdown","children":[{"id":"61915a86-d3b0-44d8-a93e-dc41bbe03fc9","format":"markdown","children":[],"title":[["Code",":q"],["Plain"," - quit (short for "],["Code",":quit"],["Plain",")"]],"body":[],"content":"``:q`` - quit (short for ``:quit``)"},{"id":"61915a86-e2f3-41ec-9ec8-7b8030f05cea","format":"markdown","children":[],"title":[["Code",":q!"],["Plain"," - quit without saving"]],"body":[],"content":"``:q!`` - quit without saving"},{"id":"61915a86-ca8f-48ef-a360-e13cdbffb527","format":"markdown","children":[],"title":[["Code",":qa"],["Plain"," - quit all"]],"body":[],"content":"``:qa`` - quit all"},{"id":"61915a86-3711-4e0e-9104-02fb4c524f6d","format":"markdown","children":[],"title":[["Code",":wq"],["Plain"," - write (save) and quit"]],"body":[],"content":"``:wq`` - write (save) and quit"},{"id":"61915a86-230b-4260-beb2-a8e50a783e06","format":"markdown","children":[],"title":[["Code",":wq!"],["Plain"," - write and quit even if the file is in read only mode"]],"body":[],"content":"``:wq!`` - write and quit even if the file is in read only mode"},{"id":"61915a86-e0cb-47c0-8af7-89340093adb8","format":"markdown","children":[],"title":[["Code",":x"],["Plain"," - write and quit (only writes if there are changes)"]],"body":[],"content":"``:x`` - write and quit (only writes if there are changes)"},{"id":"61915a86-6165-4184-ba77-3ba7fadf76bb","format":"markdown","children":[],"title":[["Code","ZZ"],["Plain"," - same as "],["Code",":x"]],"body":[],"content":"``ZZ`` - same as ``:x``"}],"title":[["Plain","There's a "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/iamdevloper/status/435555976687923200"}],"label":[["Plain","joke around the internet"]],"full_text":"[joke around the internet](https://twitter.com/iamdevloper/status/435555976687923200)","metadata":""}],["Plain"," that it's impossible to quit "],["Link",{"url":["Page_ref","Vim"],"label":[["Plain",""]],"full_text":"[[Vim]]","metadata":""}],["Plain",", but we'll see that it's actually not that hard. First of all, make sure that you're in "],["Emphasis",[["Bold"],[["Plain","normal mode"]]]],["Plain",". If you haven't changed any settings, you'll get to normal mode by pressing "],["Code","Esc"],["Plain",". From here you can use any of the following commands:"]],"body":[],"content":"There's a [joke around the internet](https://twitter.com/iamdevloper/status/435555976687923200) that it's impossible to quit [[Vim]], but we'll see that it's actually not that hard. First of all, make sure that you're in **normal mode**. If you haven't changed any settings, you'll get to normal mode by pressing ``Esc``. From here you can use any of the following commands:"},{"id":"61915a86-aa33-4017-964a-e7a620850015","format":"markdown","children":[],"title":[["Plain","All together that would for instance be: "],["Code","Esc:q"]],"body":[],"content":"All together that would for instance be: ``Esc:q``"},{"id":"61915a86-7267-48ad-a7e0-7fa1fd622566","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-e908-473e-b403-fc645b88f6f1","format":"markdown","children":[],"title":[["Tag",[["Plain","Vim"]]]],"body":[],"content":"#Vim"},{"id":"61915a86-6de4-4041-84c9-b29280ee4c6e","format":"markdown","children":[],"title":[["Emphasis",[["Bold"],[["Plain","ID:"]]]],["Plain"," 210609194733"]],"body":[],"content":"**ID:** 210609194733"}]},{"id":"61915a86-b560-40ef-896e-1091383b8d27","page-name":"SSR","children":[{"id":"61915a86-03fd-4bcc-9b5c-bed8b2150347","format":"markdown","children":[],"title":[["Plain","Server-side rendering"]],"body":[],"content":"Server-side rendering"}]},{"id":"61915a86-5eaa-4dd0-aab2-92a3f7b22189","page-name":"Jason Etcovich","properties":{"public":true},"children":[{"id":"61915a86-afb2-47c7-a5a8-e77e4673a55f","properties":{},"format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-3e95-4a20-bde2-1718db78b3a1","page-name":"React Query","properties":{"public":true},"children":[{"id":"61915a86-bebd-4c2e-87e3-340ba44cdccd","properties":{"public":true},"format":"markdown","children":[],"content":"public:: true\n"}]},{"id":"61915a86-c373-4836-ba78-bcbc5a404ce1","page-name":"Structure of CSS","properties":{"tags":["CSS"],"pid":210622091048},"children":[{"id":"61915bbb-0666-41d7-9daf-ed9921e42ef1","properties":{"tags":["CSS"],"pid":210622091048},"format":"markdown","children":[],"content":"tags:: CSS,\npid:: 210622091048"},{"id":"61915a86-168c-43ad-a1fb-3787afc7e788","properties":{},"format":"markdown","children":[],"title":[["Plain","The basic blocks of CSS are "],["Emphasis",[["Bold"],[["Plain","properties"]]]],["Plain"," and "],["Emphasis",[["Bold"],[["Plain","values"]]]],["Plain",". Properties are a human-readable identifiers that describe "],["Emphasis",[["Italic"],[["Plain","what"]]]],["Plain"," is being styled. Values indicate "],["Emphasis",[["Italic"],[["Plain","how"]]]],["Plain"," to style that property. When these are paired together they create a "],["Emphasis",[["Bold"],[["Plain","CSS declaration"]]]]],"body":[],"content":"The basic blocks of CSS are **properties** and **values**. Properties are a human-readable identifiers that describe _what_ is being styled. Values indicate _how_ to style that property. When these are paired together they create a **CSS declaration**"},{"id":"61915a86-f4f3-4561-a860-c466ed2bc7ae","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["/* Property: color, value: red - together they form a CSS declaration */","\n","color: red;","\n"],"language":"css","pos_meta":{"start_pos":266,"end_pos":357},"full_content":"``` css\n/* Property: color, value: red - together they form a CSS declaration */\ncolor: red;\n```"}]],"content":" ``` css\n/* Property: color, value: red - together they form a CSS declaration */\ncolor: red;\n```"},{"id":"61915a86-8a3c-463d-a903-eec4773f0316","format":"markdown","children":[],"title":[["Plain","CSS declarations are found within "],["Emphasis",[["Bold"],[["Plain","CSS declaration blocks"]]]],["Plain",". When CSS declaration blocks are paired with "],["Emphasis",[["Bold"],[["Plain","selectors"]]]],["Plain"," (or a list of selectors) they produce "],["Emphasis",[["Bold"],[["Plain","CSS rulesets"]]]],["Plain"," (or CSS rules)."]],"body":[],"content":"CSS declarations are found within **CSS declaration blocks**. When CSS declaration blocks are paired with **selectors** (or a list of selectors) they produce **CSS rulesets** (or CSS rules)."},{"id":"61915a86-cbcb-4a25-bd65-52b35012741f","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["/* p is a selector which together with the CSS declaration block creates a CSS rule */","\n","p {","\n"," /* Multiple declarations form a CSS declaration block */","\n"," background-color: black;","\n"," color: white;","\n","}","\n"],"language":"css","pos_meta":{"start_pos":566,"end_pos":775},"full_content":"``` css\n/* p is a selector which together with the CSS declaration block creates a CSS rule */\np {\n /* Multiple declarations form a CSS declaration block */\n background-color: black;\n color: white;\n}\n```"}]],"content":" ``` css\n/* p is a selector which together with the CSS declaration block creates a CSS rule */\np {\n /* Multiple declarations form a CSS declaration block */\n background-color: black;\n color: white;\n}\n```"},{"id":"61915a86-0d20-4a6e-9ed1-08b90d054736","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-d474-44f1-921b-4a20967d3bdf","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","MDN"],"label":[["Plain",""]],"full_text":"[[MDN]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","How CSS is structured"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured"}],"label":[["Plain","Link"]],"full_text":"[Link](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured)","metadata":""}]],"body":[],"content":"[[MDN]]. _How CSS is structured_. [Link](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured)"}]},{"id":"61915a86-b2df-4ff1-976d-b09993a9ca33","page-name":"Prettier","properties":{"public":true},"children":[{"id":"61915a86-4c3c-4c72-ad1c-0ab3164290d2","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-5f46-446e-b810-ed8f2470626f","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-97c6-4cd1-88f0-c30ab5025027","page-name":"2021-07-16","children":[{"id":"61915a86-f687-4864-900f-bb0b005a61f7","properties":{"doing":1628021490866,"done":1628021491672},"format":"markdown","children":[],"title":[["Plain","Transfer "],["Link",{"url":["Page_ref","Good documentation is written by and for humans"],"label":[["Plain",""]],"full_text":"[[Good documentation is written by and for humans]]","metadata":""}],["Plain"," by "],["Link",{"url":["Page_ref","Jason Etcovich"],"label":[["Plain",""]],"full_text":"[[Jason Etcovich]]","metadata":""}]],"body":[],"content":"DONE Transfer [[Good documentation is written by and for humans]] by [[Jason Etcovich]]\ndoing:: 1628021490866\ndone:: 1628021491672"}]},{"id":"61915a86-7f89-4299-979f-b7ab7d69f3d9","page-name":"2021-06-16","children":[{"id":"61915a86-8a1b-4adc-89ad-d5f88b86a1eb","format":"markdown","children":[],"title":[["Plain","Today I held a workshop in testing for my team at "],["Link",{"url":["Page_ref","Hemnet"],"label":[["Plain",""]],"full_text":"[[Hemnet]]","metadata":""}],["Plain",". All the descriptions, code, and explanations are available on the page "],["Link",{"url":["Page_ref","Frontend testing workshop"],"label":[["Plain",""]],"full_text":"[[Frontend testing workshop]]","metadata":""}]],"body":[],"content":"Today I held a workshop in testing for my team at [[Hemnet]]. All the descriptions, code, and explanations are available on the page [[Frontend testing workshop]]"},{"id":"61915a86-05a4-494e-a2d8-53fd9e195071","format":"markdown","children":[{"id":"61915a86-e175-42c4-8a54-b61c53d817e2","format":"markdown","children":[],"title":[["Plain","Make many small commits instead of a few large ones. This will make the PR read more as a story of what happened which is a good compliment to a good description."]],"body":[],"content":"Make many small commits instead of a few large ones. This will make the PR read more as a story of what happened which is a good compliment to a good description."}],"title":[["Link",{"url":["Page_ref","Implementing a strong code-review culture"],"label":[["Plain",""]],"full_text":"[[Implementing a strong code-review culture]]","metadata":""}]],"body":[],"content":"[[Implementing a strong code-review culture]]"}]},{"id":"61915a86-a7ed-4a9a-b2cc-e3869a0c90b5","page-name":"2021-06-09","properties":{"public":true},"children":[{"id":"61915a86-d3e0-4cff-bb20-49b774b837ff","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Rewriting Git commit history"],"label":[["Plain",""]],"full_text":"[[Rewriting Git commit history]]","metadata":""}]],"body":[],"content":"[[Rewriting Git commit history]]"},{"id":"61915a86-d74e-4e89-8280-eb46f75d533e","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Write useful error messages"],"label":[["Plain",""]],"full_text":"[[Write useful error messages]]","metadata":""}]],"body":[],"content":"[[Write useful error messages]]"},{"id":"61915a86-7ea9-4b3e-b2ec-38d6e7e4b957","properties":{},"format":"markdown","children":[{"id":"61915a86-e741-4dd7-891b-2c21e428ea44","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["type Server = 'dev' | 'stage' | 'production'","\n","\t ","\n","// Index signature","\n","const serversIndex: { [key in Server]: string } = {","\n"," dev: 'url-dev',","\n"," stage: 'url-stage',","\n"," production: 'url-production'","\n","} as const","\n","\t ","\n","// Using the Record utility","\n","const serversRecord: Record<Server, string> = {","\n"," dev: 'url-dev',","\n"," stage: 'url-stage',","\n"," production: 'url-production'","\n","} as const","\n"],"language":"ts","pos_meta":{"start_pos":301,"end_pos":707},"full_content":"```ts\ntype Server = 'dev' | 'stage' | 'production'\n\n// Index signature\nconst serversIndex: { [key in Server]: string } = {\n dev: 'url-dev',\n stage: 'url-stage',\n production: 'url-production'\n} as const\n\n// Using the Record utility\nconst serversRecord: Record<Server, string> = {\n dev: 'url-dev',\n stage: 'url-stage',\n production: 'url-production'\n} as const\n```"}]],"content":"\t ```ts\ntype Server = 'dev' | 'stage' | 'production'\n\n// Index signature\nconst serversIndex: { [key in Server]: string } = {\n dev: 'url-dev',\n stage: 'url-stage',\n production: 'url-production'\n} as const\n\n// Using the Record utility\nconst serversRecord: Record<Server, string> = {\n dev: 'url-dev',\n stage: 'url-stage',\n production: 'url-production'\n} as const\n```"},{"id":"61915a86-30b8-4f94-85c8-ba7b389edd0e","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"www.typescriptlang.org/play?#code/C4TwDgpgBAyhBOA3BUC8UDkATCiNQB9MBnYAQwHMJ8iMx4B7LAVwGNgBLBgOwwCg+rHqSjEEyeMQBcUAN5QA2gGsIIKB26xxCALozS8DRSgBfNHL5QoORDIzN4AGwC0NjABpLo8lTsOXpJTUnlb0TGycPH5OzmEs7Fy8fGZkxFBC3KQCGSJiSAgAotyIHIzcALYQ3MDSUABKEELwWAA8cPnw7t6G3BQAfOayXjbRLm4h3kGjzoFUHl5xEYnTiwk8-ClpOcAA3HxAA"}],"label":[["Plain","TS Playground"]],"full_text":"[TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAyhBOA3BUC8UDkATCiNQB9MBnYAQwHMJ8iMx4B7LAVwGNgBLBgOwwCg+rHqSjEEyeMQBcUAN5QA2gGsIIKB26xxCALozS8DRSgBfNHL5QoORDIzN4AGwC0NjABpLo8lTsOXpJTUnlb0TGycPH5OzmEs7Fy8fGZkxFBC3KQCGSJiSAgAotyIHIzcALYQ3MDSUABKEELwWAA8cPnw7t6G3BQAfOayXjbRLm4h3kGjzoFUHl5xEYnTiwk8-ClpOcAA3HxAA)","metadata":""}]],"body":[],"content":"[TS Playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAyhBOA3BUC8UDkATCiNQB9MBnYAQwHMJ8iMx4B7LAVwGNgBLBgOwwCg+rHqSjEEyeMQBcUAN5QA2gGsIIKB26xxCALozS8DRSgBfNHL5QoORDIzN4AGwC0NjABpLo8lTsOXpJTUnlb0TGycPH5OzmEs7Fy8fGZkxFBC3KQCGSJiSAgAotyIHIzcALYQ3MDSUABKEELwWAA8cPnw7t6G3BQAfOayXjbRLm4h3kGjzoFUHl5xEYnTiwk8-ClpOcAA3HxAA)"}],"title":[["Plain","In "],["Link",{"url":["Page_ref","TypeScript"],"label":[["Plain",""]],"full_text":"[[TypeScript]]","metadata":""}],["Plain"," there are two syntaxes (are there more?) for defining a type of an "],["Code","object"],["Plain",", either "],["Link",{"url":["Page_ref","Index signature"],"label":[["Plain",""]],"full_text":"[[Index signature]]","metadata":""}],["Plain"," or the "],["Link",{"url":["Page_ref","Record utility"],"label":[["Plain",""]],"full_text":"[[Record utility]]","metadata":""}],["Plain",". In my opinion, the Record syntax is more readable."]],"body":[],"content":"In [[TypeScript]] there are two syntaxes (are there more?) for defining a type of an `object`, either [[Index signature]] or the [[Record utility]]. In my opinion, the Record syntax is more readable."}]},{"id":"61915a86-4f1d-4e76-bb84-055e3a93d7d5","page-name":"Learn by doing side projects","properties":{"tags":["Learning"],"pid":210611104633},"children":[{"id":"61915a86-0912-4256-9441-68dfb6aa64fa","properties":{"tags":["Learning"],"pid":210611104633},"format":"markdown","children":[],"content":"tags:: Learning,\npid:: 210611104633"},{"id":"61915a86-ad24-4aa5-990f-213366f3aa8f","format":"markdown","children":[],"title":[["Plain","I think I can honestly say that building a bunch of side projects has made me a better developer. I get to actively work on different problems, try new things and improve my knowledge."]],"body":[],"content":"I think I can honestly say that building a bunch of side projects has made me a better developer. I get to actively work on different problems, try new things and improve my knowledge."},{"id":"61915a86-79b2-4e22-80f8-4a90f8ac6779","format":"markdown","children":[],"title":[["Plain","Have "],["Emphasis",[["Bold"],[["Plain","one specific project"]]]],["Plain",", a project you know "],["Emphasis",[["Italic"],[["Plain","exactly"]]]],["Plain"," how you want it to work, to test out new ideas, technology and frameworks on. If it contains multiple parts, like interacting with an "],["Link",{"url":["Page_ref","API"],"label":[["Plain",""]],"full_text":"[[API]]","metadata":""}],["Plain"," or how to contain state, it's a perfect project to evaluate new technologies with."]],"body":[],"content":"Have **one specific project**, a project you know _exactly_ how you want it to work, to test out new ideas, technology and frameworks on. If it contains multiple parts, like interacting with an [[API]] or how to contain state, it's a perfect project to evaluate new technologies with."},{"id":"61915a86-9bf2-44a6-886d-a4d6fde8667a","format":"markdown","children":[],"title":[["Plain","You can potentially learn even more by "],["Link",{"url":["Page_ref","Learning in public"],"label":[["Plain",""]],"full_text":"[[Learning in public]]","metadata":""}]],"body":[],"content":"You can potentially learn even more by [[Learning in public]]"}]},{"id":"61915a86-ea17-4f16-9154-8eb0db46096a","page-name":"Internet Explorer","properties":{"alias":["IE"]},"children":[{"id":"61915a86-e9d0-4a35-a72a-2747cf2c8289","properties":{"alias":["IE"]},"format":"markdown","children":[],"content":"alias:: IE,\n"}]},{"id":"61915a86-1e42-4604-94e3-0823b5a4c56a","page-name":"Rubber ducking","properties":{"tags":["Teaching","Learning"]},"children":[{"id":"61915ce4-fb41-4182-b4d5-408df1c71052","properties":{"tags":["Teaching","Learning"]},"format":"markdown","children":[],"content":"tags:: Teaching, Learning"},{"id":"61915a86-7be5-473b-97e6-aaa45c89285d","properties":{},"format":"markdown","children":[],"title":[["Emphasis",[["Italic"],[["Plain","Rubber ducking"]]]],["Plain"," is the process of explaining your problem to another human or even an inanimate object like a plastic duck (hence the name). By putting the problem into words you might see issues that you've missed by only writing the code."]],"body":[],"content":"_Rubber ducking_ is the process of explaining your problem to another human or even an inanimate object like a plastic duck (hence the name). By putting the problem into words you might see issues that you've missed by only writing the code."},{"id":"61915a86-df54-46b4-ab87-d30936ee6887","format":"markdown","children":[],"title":[["Plain","Try to think the problem through and "],["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}]],"body":[],"content":"Try to think the problem through and [[Explain in plain words]]"}]},{"id":"61915a86-a177-4014-8c59-d2f07a55aa93","page-name":"Falsy in JavaScript","properties":{"alias":["falsy"],"title":"Falsy in JavaScript","tags":["JavaScript"]},"children":[{"id":"61915a86-0e09-4d66-b500-b5e228aee83f","properties":{"alias":["falsy"],"title":"Falsy in JavaScript","tags":["JavaScript"]},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"alias:: falsy\ntitle:: Falsy in JavaScript\ntags:: JavaScript,\n\n"},{"id":"61915a86-9451-4b57-b0f1-382ff324f5e8","format":"markdown","children":[],"title":[["Plain","Empty string"]],"body":[],"content":"Empty string"},{"id":"61915a86-96fd-49e3-9635-e2de72050c17","format":"markdown","children":[],"title":[["Plain","0 and -0"]],"body":[],"content":"0 and -0"},{"id":"61915a86-3dc2-43ab-b67b-b1980d8cd7c6","format":"markdown","children":[],"title":[["Code","false"]],"body":[],"content":"`false`"},{"id":"61915a86-0e6a-4f1a-95eb-37099a771a8d","format":"markdown","children":[],"title":[["Code","undefined"]],"body":[],"content":"``undefined``"},{"id":"61915a86-5e2c-484c-a297-03dc97032911","format":"markdown","children":[],"title":[["Code","null"]],"body":[],"content":"``null``"}]},{"id":"61915a86-559e-422b-be73-0302d2efa275","page-name":"2020-10-23","properties":{"public":true},"children":[{"id":"61915a86-2878-474f-8d59-93553f3d3ff5","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-d450-4b0f-a5dd-941dc58e370d","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-4dbe-438f-bdf4-0f23f1ae3e06","page-name":"Frontend testing workshop","children":[{"id":"61915a86-755c-42c7-b8cb-4c73820326ea","format":"markdown","children":[],"title":[["Plain","This is a workshop in "],["Link",{"url":["Page_ref","Frontend"],"label":[["Plain",""]],"full_text":"[[Frontend]]","metadata":""}],["Plain"," "],["Link",{"url":["Page_ref","Testing"],"label":[["Plain",""]],"full_text":"[[Testing]]","metadata":""}],["Plain"," that I held at "],["Link",{"url":["Page_ref","Hemnet"],"label":[["Plain",""]],"full_text":"[[Hemnet]]","metadata":""}],["Plain",". The idea was to have it sort of like a "],["Link",{"url":["Page_ref","Mob programming"],"label":[["Plain",""]],"full_text":"[[Mob programming]]","metadata":""}],["Plain"," session so that each participant got to code and get a feel for the code instead of just sitting and listening to me talk about it."]],"body":[],"content":"This is a workshop in [[Frontend]] [[Testing]] that I held at [[Hemnet]]. The idea was to have it sort of like a [[Mob programming]] session so that each participant got to code and get a feel for the code instead of just sitting and listening to me talk about it."},{"id":"61915a86-1b22-43ff-94c7-aa3fe94277e4","format":"markdown","children":[],"title":[["Plain","The focus of the workshop was for the participants to get better knowledge in testing some of the more uncommon/advanced testing paths."]],"body":[],"content":"The focus of the workshop was for the participants to get better knowledge in testing some of the more uncommon/advanced testing paths."},{"id":"61915a86-64cd-4738-a8b3-685e57d7340f","format":"markdown","children":[],"title":[["Plain","The code is available at "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop"}],"label":[["Plain","believer/frontend-testing-workshop"]],"full_text":"[believer/frontend-testing-workshop](https://github.com/believer/frontend-testing-workshop)","metadata":""}],["Plain"," and split into three branches: "],["Code","1-context"],["Plain",", "],["Code","2-async"],["Plain"," and "],["Code","3-hooks"],["Plain",". Each branch also has a sibling with the completed state for that scenario. The completed branch names are the same but with "],["Code","-complete"],["Plain"," added at the end, e.g. "],["Code","1-context-complete"],["Plain","."]],"body":[],"content":"The code is available at [believer/frontend-testing-workshop](https://github.com/believer/frontend-testing-workshop) and split into three branches: `1-context`, `2-async` and `3-hooks`. Each branch also has a sibling with the completed state for that scenario. The completed branch names are the same but with `-complete` added at the end, e.g. `1-context-complete`."},{"id":"61915a86-b6d7-4279-9bf2-1c22e5f06132","format":"markdown","children":[],"title":[["Plain","We're using "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain",", "],["Link",{"url":["Page_ref","Jest"],"label":[["Plain",""]],"full_text":"[[Jest]]","metadata":""}],["Plain",", "],["Link",{"url":["Page_ref","Testing Library"],"label":[["Plain",""]],"full_text":"[[Testing Library]]","metadata":""}],["Plain",", and "],["Link",{"url":["Page_ref","React Query"],"label":[["Plain",""]],"full_text":"[[React Query]]","metadata":""}],["Plain","."]],"body":[],"content":"We're using [[React]], [[Jest]], [[Testing Library]], and [[React Query]]."},{"id":"61915a86-441f-4d5a-8be5-8a3db3d42b7a","heading-level":3,"format":"markdown","children":[{"id":"61915a86-0748-40c5-9a32-13653d35d41a","format":"markdown","children":[],"title":[["Link",{"url":["Search","#Context"],"label":[["Plain","Context"]],"full_text":"[Context](#Context)","metadata":""}]],"body":[],"content":"[Context](#Context)"},{"id":"61915a86-c924-4225-87ae-48b5862c334d","format":"markdown","children":[],"title":[["Link",{"url":["Search","#Async"],"label":[["Plain","Async"]],"full_text":"[Async](#Async)","metadata":""}]],"body":[],"content":"[Async](#Async)"},{"id":"61915a86-bd8e-407b-9620-fdbb1d4bf77c","format":"markdown","children":[],"title":[["Link",{"url":["Search","#Custom-hooks"],"label":[["Plain","Custom hooks"]],"full_text":"[Custom hooks](#Custom-hooks)","metadata":""}]],"body":[],"content":"[Custom hooks](#Custom-hooks)"}],"title":[["Plain","Sections"]],"body":[],"content":"### Sections"},{"id":"61915a86-8b74-407a-8f7c-90d16d60a9bf","heading-level":3,"format":"markdown","children":[{"id":"61915a86-45ab-4f41-a16b-6bf044db5c0b","format":"markdown","children":[],"title":[["Plain","We'll start off by testing "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain","'s context. The full starting code is available in the "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop"}],"label":[["Plain","testing repo"]],"full_text":"[testing repo](https://github.com/believer/frontend-testing-workshop)","metadata":""}],["Plain",". The relevant code are these three files where we have set up a tiny application with a "],["Code","<Text>"],["Plain"," component that gets a text from the context and displays it to the user."]],"body":[],"content":"We'll start off by testing [[React]]'s context. The full starting code is available in the [testing repo](https://github.com/believer/frontend-testing-workshop). The relevant code are these three files where we have set up a tiny application with a `<Text>` component that gets a text from the context and displays it to the user."},{"id":"61915a86-b3bd-4e21-90db-123b79d2ed17","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// AppContext.js","\n","import React from 'react'","\n","\t ","\n","// Create a React context and set the default text value to an empty string","\n","export const AppContext = React.createContext({","\n"," text: '',","\n","})","\n","\t ","\n","// Create a custom hook to make it easier to access the context","\n","export const useApp = () => React.useContext(AppContext)","\n"],"language":"js","pos_meta":{"start_pos":1297,"end_pos":1641},"full_content":"```js\n// AppContext.js\nimport React from 'react'\n\t \n// Create a React context and set the default text value to an empty string\nexport const AppContext = React.createContext({\n text: '',\n})\n\t \n// Create a custom hook to make it easier to access the context\nexport const useApp = () => React.useContext(AppContext)\n```"}]],"content":"\t ```js\n// AppContext.js\nimport React from 'react'\n\t \n// Create a React context and set the default text value to an empty string\nexport const AppContext = React.createContext({\n text: '',\n})\n\t \n// Create a custom hook to make it easier to access the context\nexport const useApp = () => React.useContext(AppContext)\n```"},{"id":"61915a86-a7d9-40f2-83ae-d61868edcf12","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.js","\n","import { AppContext, useApp } from './AppContext'","\n","\t ","\n","export const Text = () => {","\n"," const { text } = useApp()","\n","\t ","\n"," return <div>{text}</div>","\n","}","\n","\t ","\n","export default function App({ text }) {","\n"," return (","\n"," <AppContext.Provider value={{ text }}>","\n"," <Text />","\n"," </AppContext.Provider>","\n"," )","\n","}","\n"],"language":"js","pos_meta":{"start_pos":1657,"end_pos":1998},"full_content":"```js\n// App.js\nimport { AppContext, useApp } from './AppContext'\n\nexport const Text = () => {\n const { text } = useApp()\n\n return <div>{text}</div>\n}\n\nexport default function App({ text }) {\n return (\n <AppContext.Provider value={{ text }}>\n <Text />\n </AppContext.Provider>\n )\n}\n```"}]],"content":"\t ```js\n// App.js\nimport { AppContext, useApp } from './AppContext'\n\nexport const Text = () => {\n const { text } = useApp()\n\n return <div>{text}</div>\n}\n\nexport default function App({ text }) {\n return (\n <AppContext.Provider value={{ text }}>\n <Text />\n </AppContext.Provider>\n )\n}\n```"},{"id":"61915a86-51d8-439b-a8e9-2ff5b35492f5","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","import App, { Text } from './App'","\n","import { screen, render } from '@testing-library/react'","\n","\t ","\n","// All the tests we'll create prepared as TODOs","\n","test.todo('renders app')","\n","test.todo('Text using a mocked useApp hook')","\n","test.todo('Text by importing the context')","\n"],"language":"js","pos_meta":{"start_pos":2014,"end_pos":2311},"full_content":"```js\n// App.test.js\nimport App, { Text } from './App'\nimport { screen, render } from '@testing-library/react'\n\t \n// All the tests we'll create prepared as TODOs\ntest.todo('renders app')\ntest.todo('Text using a mocked useApp hook')\ntest.todo('Text by importing the context')\n```"}]],"content":"\t ```js\n// App.test.js\nimport App, { Text } from './App'\nimport { screen, render } from '@testing-library/react'\n\t \n// All the tests we'll create prepared as TODOs\ntest.todo('renders app')\ntest.todo('Text using a mocked useApp hook')\ntest.todo('Text by importing the context')\n```"},{"id":"61915a86-18d7-490f-a5ed-b44ea5ee2e41","format":"markdown","children":[],"title":[["Plain","Let's start with the first test, that the app renders correctly."]],"body":[],"content":"Let's start with the first test, that the app renders correctly."},{"id":"61915a86-52fb-41ab-a7e5-496546c3f75f","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","\t ","\n","test('renders app', () => {","\n"," // Render the App component and pass a text prop","\n"," // The text prop is added to the context","\n"," render(<App text=\"Frontend testing is fun!\" />)","\n","\t ","\n"," // Assert that the document contains a text with the value","\n"," // that we passed to the context. The toBeInTheDocument assertion comes","\n"," // from @testing-library/jest-dom","\n"," expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":2395,"end_pos":2872},"full_content":"```js\n// App.test.js\n\ntest('renders app', () => {\n // Render the App component and pass a text prop\n // The text prop is added to the context\n render(<App text=\"Frontend testing is fun!\" />)\n\n // Assert that the document contains a text with the value\n // that we passed to the context. The toBeInTheDocument assertion comes\n // from @testing-library/jest-dom\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\n// App.test.js\n\ntest('renders app', () => {\n // Render the App component and pass a text prop\n // The text prop is added to the context\n render(<App text=\"Frontend testing is fun!\" />)\n\n // Assert that the document contains a text with the value\n // that we passed to the context. The toBeInTheDocument assertion comes\n // from @testing-library/jest-dom\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"},{"id":"61915a86-b92f-404f-8f3e-3795d02e1c34","format":"markdown","children":[],"title":[["Plain","Next, we want to try render the "],["Code","<Text>"],["Plain"," component in isolation and here's where we'll start seeing some issues. If we just try to render the component, "],["Code","render(<Text />)"],["Plain",", and use the same assertion as above we'll get an error that the text can't be found. This happens because the "],["Code","<Text>"],["Plain"," component is no longer wrapped in a React context and it get's the default value for "],["Code","text"],["Plain"," which we defined in when creating the context using "],["Code","React.createContext"],["Plain","."]],"body":[],"content":"Next, we want to try render the `<Text>` component in isolation and here's where we'll start seeing some issues. If we just try to render the component, `render(<Text />)`, and use the same assertion as above we'll get an error that the text can't be found. This happens because the `<Text>` component is no longer wrapped in a React context and it get's the default value for `text` which we defined in when creating the context using `React.createContext`."},{"id":"61915a86-d9a5-4351-8788-0139e052c8fd","format":"markdown","children":[],"title":[["Plain","To get around this we'll need some way of getting the data to the component. Our first attempt will be to mock the response of the custom hook, "],["Code","useApp"],["Plain",", that we've defined for our context."]],"body":[],"content":"To get around this we'll need some way of getting the data to the component. Our first attempt will be to mock the response of the custom hook, `useApp`, that we've defined for our context."},{"id":"61915a86-1a62-4495-ba05-385161f24767","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","// This import will be a mocked version as defined by jest.mock below","\n","import { useApp } from './AppContext'","\n","\t\t \t\t ","\n","// This is a mock that automatically determines what the file contains","\n","// and provides mocked functions for each exported value","\n","jest.mock('./AppContext')","\n","\t ","\n","// Mock the response of the useApp hook before each test runs","\n","beforeEach(() => {","\n"," useApp.mockReturnValue({","\n"," text: 'Frontend testing is fun!',","\n"," })","\n","})","\n","\t\t ","\n","test('Text using a mocked useApp hook', () => {","\n"," // Render the Text component","\n"," render(<Text />)","\n","\t\t \t\t ","\n"," // Since the useApp hook is now mocked, we'll get a passing text","\n"," expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":3543,"end_pos":4310},"full_content":"```js\n// App.test.js\n// This import will be a mocked version as defined by jest.mock below\nimport { useApp } from './AppContext'\n\t\t \t\t \n// This is a mock that automatically determines what the file contains\n// and provides mocked functions for each exported value\njest.mock('./AppContext')\n\n// Mock the response of the useApp hook before each test runs\nbeforeEach(() => {\n useApp.mockReturnValue({\n text: 'Frontend testing is fun!',\n })\n})\n\t\t \ntest('Text using a mocked useApp hook', () => {\n // Render the Text component\n render(<Text />)\n\t\t \t\t \n // Since the useApp hook is now mocked, we'll get a passing text\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\n// App.test.js\n// This import will be a mocked version as defined by jest.mock below\nimport { useApp } from './AppContext'\n\t\t \t\t \n// This is a mock that automatically determines what the file contains\n// and provides mocked functions for each exported value\njest.mock('./AppContext')\n\n// Mock the response of the useApp hook before each test runs\nbeforeEach(() => {\n useApp.mockReturnValue({\n text: 'Frontend testing is fun!',\n })\n})\n\t\t \ntest('Text using a mocked useApp hook', () => {\n // Render the Text component\n render(<Text />)\n\t\t \t\t \n // Since the useApp hook is now mocked, we'll get a passing text\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"},{"id":"61915a86-658e-4673-9c57-78cc73f611b8","format":"markdown","children":[],"title":[["Plain","This works fine. However, if we were to remove the "],["Code","text"],["Plain"," prop from our first test and only use "],["Code","render(<App />)"],["Plain"," that test would still pass! That is because we've effectively mocked the entire context for all tests, which is not really want we want."]],"body":[],"content":"This works fine. However, if we were to remove the `text` prop from our first test and only use `render(<App />)` that test would still pass! That is because we've effectively mocked the entire context for all tests, which is not really want we want."},{"id":"61915a86-6f33-4422-a0eb-4159a11e03ed","format":"markdown","children":[],"title":[["Plain","Let's try it another way. This time by adding the context inside our test."]],"body":[],"content":"Let's try it another way. This time by adding the context inside our test."},{"id":"61915a86-2f9e-4240-8a51-aeb1ddbfbb54","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","// Import the AppContext, note that this is the real version and","\n","// not a mocked version","\n","import { AppContext } from './AppContext'","\n","\t ","\n","test('Text by importing the context', () => {","\n"," // Wrap our Text component in the AppContext.Provider and","\n"," // provide it with the value we want displayed in the Text component","\n"," render(","\n"," <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>","\n"," <Text />","\n"," </AppContext.Provider>","\n"," )","\n","\t ","\n"," expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":4658,"end_pos":5238},"full_content":"```js\n// App.test.js\n// Import the AppContext, note that this is the real version and\n// not a mocked version\nimport { AppContext } from './AppContext'\n\ntest('Text by importing the context', () => {\n // Wrap our Text component in the AppContext.Provider and\n // provide it with the value we want displayed in the Text component\n render(\n <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>\n <Text />\n </AppContext.Provider>\n )\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\n// App.test.js\n// Import the AppContext, note that this is the real version and\n// not a mocked version\nimport { AppContext } from './AppContext'\n\ntest('Text by importing the context', () => {\n // Wrap our Text component in the AppContext.Provider and\n // provide it with the value we want displayed in the Text component\n render(\n <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>\n <Text />\n </AppContext.Provider>\n )\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"},{"id":"61915a86-47c0-4c90-b1d2-70291f206280","format":"markdown","children":[],"title":[["Plain","Now this is much better. Now we're not messing with the first test and are instead asserting that the "],["Code","Text"],["Plain"," component works using the correct context. This is a trivial example, but for bigger contexts that are used across multiple files this would be a great solution for testing in isolation but still maintaining the integration testing aspect."]],"body":[],"content":"Now this is much better. Now we're not messing with the first test and are instead asserting that the `Text` component works using the correct context. This is a trivial example, but for bigger contexts that are used across multiple files this would be a great solution for testing in isolation but still maintaining the integration testing aspect."},{"id":"61915a86-bd8b-42f7-afe0-7e6d9cb5826b","format":"markdown","children":[],"title":[["Plain","The final code for our tests looks like this and it's available in the repo on the branch "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop/tree/1-context-complete"}],"label":[["Code","1-context-complete"]],"full_text":"[`1-context-complete`](https://github.com/believer/frontend-testing-workshop/tree/1-context-complete)","metadata":""}]],"body":[],"content":"The final code for our tests looks like this and it's available in the repo on the branch [`1-context-complete`](https://github.com/believer/frontend-testing-workshop/tree/1-context-complete)"},{"id":"61915a86-55ce-4e41-8aab-56834c33e81a","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["import App, { Text } from './App'","\n","import { screen, render } from '@testing-library/react'","\n","import { AppContext } from './AppContext'","\n","\t ","\n","test('renders app', () => {","\n"," render(<App text=\"Frontend testing is fun!\" />)","\n","\t ","\n"," expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()","\n","})","\n","\t ","\n","test('Text by importing the context', () => {","\n"," render(","\n"," <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>","\n"," <Text />","\n"," </AppContext.Provider>","\n"," )","\n","\t ","\n"," expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":5801,"end_pos":6403},"full_content":"```js\nimport App, { Text } from './App'\nimport { screen, render } from '@testing-library/react'\nimport { AppContext } from './AppContext'\n\ntest('renders app', () => {\n render(<App text=\"Frontend testing is fun!\" />)\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n\ntest('Text by importing the context', () => {\n render(\n <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>\n <Text />\n </AppContext.Provider>\n )\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\nimport App, { Text } from './App'\nimport { screen, render } from '@testing-library/react'\nimport { AppContext } from './AppContext'\n\ntest('renders app', () => {\n render(<App text=\"Frontend testing is fun!\" />)\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n\ntest('Text by importing the context', () => {\n render(\n <AppContext.Provider value={{ text: 'Frontend testing is fun' }}>\n <Text />\n </AppContext.Provider>\n )\n\n expect(screen.getByText(/frontend testing is fun/i)).toBeInTheDocument()\n})\n```"}],"title":[["Plain","Context"]],"body":[],"content":"### Context"},{"id":"61915a86-756c-4998-b692-8d3b53d37e31","heading-level":3,"format":"markdown","children":[{"id":"61915a86-2019-4080-8d37-27d493f6f0f5","format":"markdown","children":[],"title":[["Plain","For our second testing scenario we are going to test an asynchronous hook. For this we'll use "],["Code","react-query"],["Plain","'s "],["Code","useQuery"],["Plain"," hook and fetch a character from the Star Wars "],["Link",{"url":["Page_ref","API"],"label":[["Plain",""]],"full_text":"[[API]]","metadata":""}],["Plain",". The code is on the branch "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop/tree/2-async"}],"label":[["Code","2-async"]],"full_text":"[`2-async`](https://github.com/believer/frontend-testing-workshop/tree/2-async)","metadata":""}],["Plain",". This is what we're starting out with"]],"body":[],"content":"For our second testing scenario we are going to test an asynchronous hook. For this we'll use `react-query`'s `useQuery` hook and fetch a character from the Star Wars [[API]]. The code is on the branch [`2-async`](https://github.com/believer/frontend-testing-workshop/tree/2-async). This is what we're starting out with"},{"id":"61915a86-b282-4d92-bce9-498e96a7fba7","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.js","\n","import { useQuery, QueryClient, QueryClientProvider } from 'react-query'","\n","\t ","\n","// Create a client for making queries","\n","const queryClient = new QueryClient()","\n","\t ","\n","// Call the Star Wars API and return the JSON data","\n","// This can be any function, as long as it returns a promise","\n","const fetchLuke = async () => {","\n"," const response = await fetch('https://swapi.dev/api/people/1/')","\n"," return response.json()","\n","}","\n","\t ","\n","const Luke = () => {","\n"," // Set up the useQuery hook with a unique key, 'luke', which is used","\n"," // for caching and pass our fetching function","\n"," const { isLoading, data } = useQuery('luke', fetchLuke)","\n","\t ","\n"," // Loading state","\n"," if (isLoading) {","\n"," return <div>Loading...</div>","\n"," }","\n","\t ","\n"," // Display the name of the character","\n"," return <div>{data.name}</div>","\n","}","\n","\t ","\n","export default function App() {","\n"," return (","\n"," // Set up the provider with the client we created","\n"," <QueryClientProvider client={queryClient}>","\n"," <Luke />","\n"," </QueryClientProvider>","\n"," )","\n","}","\n"],"language":"js","pos_meta":{"start_pos":6752,"end_pos":7800},"full_content":"```js\n// App.js\nimport { useQuery, QueryClient, QueryClientProvider } from 'react-query'\n\n// Create a client for making queries\nconst queryClient = new QueryClient()\n\n// Call the Star Wars API and return the JSON data\n// This can be any function, as long as it returns a promise\nconst fetchLuke = async () => {\n const response = await fetch('https://swapi.dev/api/people/1/')\n return response.json()\n}\n\nconst Luke = () => {\n // Set up the useQuery hook with a unique key, 'luke', which is used\n // for caching and pass our fetching function\n const { isLoading, data } = useQuery('luke', fetchLuke)\n\n // Loading state\n if (isLoading) {\n return <div>Loading...</div>\n }\n\n // Display the name of the character\n return <div>{data.name}</div>\n}\n\nexport default function App() {\n return (\n // Set up the provider with the client we created\n <QueryClientProvider client={queryClient}>\n <Luke />\n </QueryClientProvider>\n )\n}\n```"}]],"content":"\t ```js\n// App.js\nimport { useQuery, QueryClient, QueryClientProvider } from 'react-query'\n\n// Create a client for making queries\nconst queryClient = new QueryClient()\n\n// Call the Star Wars API and return the JSON data\n// This can be any function, as long as it returns a promise\nconst fetchLuke = async () => {\n const response = await fetch('https://swapi.dev/api/people/1/')\n return response.json()\n}\n\nconst Luke = () => {\n // Set up the useQuery hook with a unique key, 'luke', which is used\n // for caching and pass our fetching function\n const { isLoading, data } = useQuery('luke', fetchLuke)\n\n // Loading state\n if (isLoading) {\n return <div>Loading...</div>\n }\n\n // Display the name of the character\n return <div>{data.name}</div>\n}\n\nexport default function App() {\n return (\n // Set up the provider with the client we created\n <QueryClientProvider client={queryClient}>\n <Luke />\n </QueryClientProvider>\n )\n}\n```"},{"id":"61915a86-1af7-44d2-a762-276bd8a3c3d5","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","import App from './App'","\n","import { screen, render } from '@testing-library/react'","\n","\t ","\n","test.todo('renders loading state')","\n","test.todo('renders data')","\n"],"language":"js","pos_meta":{"start_pos":7816,"end_pos":7994},"full_content":"```js\n// App.test.js\nimport App from './App'\nimport { screen, render } from '@testing-library/react'\n\ntest.todo('renders loading state')\ntest.todo('renders data')\n```"}]],"content":"\t ```js\n// App.test.js\nimport App from './App'\nimport { screen, render } from '@testing-library/react'\n\ntest.todo('renders loading state')\ntest.todo('renders data')\n```"},{"id":"61915a86-e2bd-4c54-a77b-226bef8f48b9","format":"markdown","children":[],"title":[["Plain","First we'll test that the loading state renders correctly. We don't need to do anything special for this case."]],"body":[],"content":"First we'll test that the loading state renders correctly. We don't need to do anything special for this case."},{"id":"61915a86-31e8-45d6-8ac0-ba6f765ed201","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// App.test.js","\n","test('renders loading state', () => {","\n"," // Render the App component","\n"," render(<App />)","\n","\t ","\n"," // Assert ","\n"," expect(screen.getByText(/loading.../i)).toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":8124,"end_pos":8331},"full_content":"```js\n// App.test.js\ntest('renders loading state', () => {\n // Render the App component\n render(<App />)\n\n // Assert \n expect(screen.getByText(/loading.../i)).toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\n// App.test.js\ntest('renders loading state', () => {\n // Render the App component\n render(<App />)\n\n // Assert \n expect(screen.getByText(/loading.../i)).toBeInTheDocument()\n})\n```"},{"id":"61915a86-894d-45a0-b971-fc05a5f1da60","format":"markdown","children":[],"title":[["Plain","Next, we'll want to make sure that the app actually display our character, Luke Skywalker. To make the test pass we only need to add async/await and use a "],["Code","findBy*"],["Plain"," query."]],"body":[],"content":"Next, we'll want to make sure that the app actually display our character, Luke Skywalker. To make the test pass we only need to add async/await and use a `findBy*` query."},{"id":"61915a86-12fd-48bf-8282-74c9c13c0c10","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// Make the test asynchronous by adding async to the callback","\n","test('renders data', async () => {","\n"," render(<App />)","\n","\t ","\n"," // Using await and a findBy* query the assertion will wait until the","\n"," // document contains the text we're looking for. If it takes too long","\n"," // the test will timeout.","\n"," expect(await screen.findByText(/luke skywalker/i)).toBeInTheDocument()","\n"," ","\n"," // This assertion checks that we're no longer rendering the loading state.","\n"," // It uses queryBy* since a getBy* or findBy* would throw errors if they","\n"," // can't find the element","\n"," expect(screen.queryByText(/loading.../)).not.toBeInTheDocument()","\n","})","\n"],"language":"js","pos_meta":{"start_pos":8522,"end_pos":9183},"full_content":"```js\n// Make the test asynchronous by adding async to the callback\ntest('renders data', async () => {\n render(<App />)\n\t \n // Using await and a findBy* query the assertion will wait until the\n // document contains the text we're looking for. If it takes too long\n // the test will timeout.\n expect(await screen.findByText(/luke skywalker/i)).toBeInTheDocument()\n \n // This assertion checks that we're no longer rendering the loading state.\n // It uses queryBy* since a getBy* or findBy* would throw errors if they\n // can't find the element\n expect(screen.queryByText(/loading.../)).not.toBeInTheDocument()\n})\n```"}]],"content":"\t ```js\n// Make the test asynchronous by adding async to the callback\ntest('renders data', async () => {\n render(<App />)\n\t \n // Using await and a findBy* query the assertion will wait until the\n // document contains the text we're looking for. If it takes too long\n // the test will timeout.\n expect(await screen.findByText(/luke skywalker/i)).toBeInTheDocument()\n \n // This assertion checks that we're no longer rendering the loading state.\n // It uses queryBy* since a getBy* or findBy* would throw errors if they\n // can't find the element\n expect(screen.queryByText(/loading.../)).not.toBeInTheDocument()\n})\n```"},{"id":"61915a86-542d-48b9-a7e3-ea3268392489","format":"markdown","children":[],"title":[["Plain","However, this would call the real API which is not ideal. The response could change, the service could be down or slow to respond. By adding a "],["Code","beforeEach"],["Plain"," with a mocked response we can ensure that our test won't be flaky."]],"body":[],"content":"However, this would call the real API which is not ideal. The response could change, the service could be down or slow to respond. By adding a `beforeEach` with a mocked response we can ensure that our test won't be flaky."},{"id":"61915a86-d880-41c6-a52c-2e99eaa54596","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["beforeEach(() => {","\n"," global.fetch = jest.fn().mockResolvedValue({","\n"," json: jest.fn().mockResolvedValue({","\n"," // Use a name we know won't be returned from the API to ensure","\n"," // that we're calling our mock. Be sure to update the assertion","\n"," // as well. Kudos to a colleague for pointing this out!","\n"," name: 'Mocked Skywalker',","\n"," }),","\n"," })","\n","})","\n"],"language":"js","pos_meta":{"start_pos":9425,"end_pos":9813},"full_content":"```js\nbeforeEach(() => {\n global.fetch = jest.fn().mockResolvedValue({\n json: jest.fn().mockResolvedValue({\n // Use a name we know won't be returned from the API to ensure\n // that we're calling our mock. Be sure to update the assertion\n // as well. Kudos to a colleague for pointing this out!\n name: 'Mocked Skywalker',\n }),\n })\n})\n```"}]],"content":"\t ```js\nbeforeEach(() => {\n global.fetch = jest.fn().mockResolvedValue({\n json: jest.fn().mockResolvedValue({\n // Use a name we know won't be returned from the API to ensure\n // that we're calling our mock. Be sure to update the assertion\n // as well. Kudos to a colleague for pointing this out!\n name: 'Mocked Skywalker',\n }),\n })\n})\n```"},{"id":"61915a86-8153-41cb-b495-038a049ae74c","format":"markdown","children":[],"title":[["Plain","The final code is available on the branch "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop/tree/2-async-complete"}],"label":[["Code","2-async-complete"]],"full_text":"[`2-async-complete`](https://github.com/believer/frontend-testing-workshop/tree/2-async-complete)","metadata":""}],["Plain","."]],"body":[],"content":"The final code is available on the branch [`2-async-complete`](https://github.com/believer/frontend-testing-workshop/tree/2-async-complete)."}],"title":[["Plain","Async"]],"body":[],"content":"### Async"},{"id":"61915a86-bcbc-45e9-a850-60e154ea9489","heading-level":3,"format":"markdown","children":[{"id":"61915a86-9427-411a-9a8b-368bf80561b7","format":"markdown","children":[],"title":[["Plain","For our third and final scenario we'll test a custom React hook. The hook we're testing is trivial, but we'll add some features using "],["Link",{"url":["Page_ref","TDD"],"label":[["Plain",""]],"full_text":"[[TDD]]","metadata":""}],["Plain"," as we go along. The code is available on the branch "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop/tree/3-hooks"}],"label":[["Code","3-hooks"]],"full_text":"[`3-hooks`](https://github.com/believer/frontend-testing-workshop/tree/3-hooks)","metadata":""}],["Plain"," and the two files we'll use are"]],"body":[],"content":"For our third and final scenario we'll test a custom React hook. The hook we're testing is trivial, but we'll add some features using [[TDD]] as we go along. The code is available on the branch [`3-hooks`](https://github.com/believer/frontend-testing-workshop/tree/3-hooks) and the two files we'll use are"},{"id":"61915a86-0643-424c-80ff-ed5371d6fc3b","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// useCustomHook.js","\n","import React from 'react'","\n","\t ","\n","export const useCustomHook = () => {","\n"," const [state] = React.useState('Initial')","\n","\t ","\n"," return state","\n","}","\n"],"language":"js","pos_meta":{"start_pos":10299,"end_pos":10472},"full_content":"```js\n// useCustomHook.js\nimport React from 'react'\n\nexport const useCustomHook = () => {\n const [state] = React.useState('Initial')\n\n return state\n}\n```"}]],"content":"\t ```js\n// useCustomHook.js\nimport React from 'react'\n\nexport const useCustomHook = () => {\n const [state] = React.useState('Initial')\n\n return state\n}\n```"},{"id":"61915a86-3b8d-4fdb-89db-e05291a9738f","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// useCustomHook.test.js","\n","import { act, renderHook } from '@testing-library/react-hooks'","\n","import { useCustomHook } from './useCustomHook'","\n","\t ","\n","test.todo('custom hook return state')","\n","test.todo('custom hook with custom initial value')","\n","test.todo('custom hook with updater')","\n"],"language":"js","pos_meta":{"start_pos":10488,"end_pos":10776},"full_content":"```js\n// useCustomHook.test.js\nimport { act, renderHook } from '@testing-library/react-hooks'\nimport { useCustomHook } from './useCustomHook'\n\ntest.todo('custom hook return state')\ntest.todo('custom hook with custom initial value')\ntest.todo('custom hook with updater')\n```"}]],"content":"\t ```js\n// useCustomHook.test.js\nimport { act, renderHook } from '@testing-library/react-hooks'\nimport { useCustomHook } from './useCustomHook'\n\ntest.todo('custom hook return state')\ntest.todo('custom hook with custom initial value')\ntest.todo('custom hook with updater')\n```"},{"id":"61915a86-4ab7-4003-aaee-4a1e17c7ae08","format":"markdown","children":[],"title":[["Plain","The first test is pretty straightforward"]],"body":[],"content":"The first test is pretty straightforward"},{"id":"61915a86-bf4d-41b5-8ede-622ec5841b27","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// useCustomHook.test.js","\n","\t ","\n","test('custom hook return state', () => {","\n"," // We use the renderHook utility to wrap our custom hook. This will return","\n"," // an object with the current value of the hook and as well as any errors","\n"," const { result } = renderHook(() => useCustomHook())","\n","\t ","\n"," // result.current is the current value that is returned","\n"," expect(result.current).toEqual('Initial')","\n","})","\n"],"language":"js","pos_meta":{"start_pos":10836,"end_pos":11250},"full_content":"```js\n// useCustomHook.test.js\n\ntest('custom hook return state', () => {\n // We use the renderHook utility to wrap our custom hook. This will return\n // an object with the current value of the hook and as well as any errors\n const { result } = renderHook(() => useCustomHook())\n\n // result.current is the current value that is returned\n expect(result.current).toEqual('Initial')\n})\n```"}]],"content":"\t ```js\n// useCustomHook.test.js\n\ntest('custom hook return state', () => {\n // We use the renderHook utility to wrap our custom hook. This will return\n // an object with the current value of the hook and as well as any errors\n const { result } = renderHook(() => useCustomHook())\n\n // result.current is the current value that is returned\n expect(result.current).toEqual('Initial')\n})\n```"},{"id":"61915a86-b875-43b3-8019-0058be5b23f5","format":"markdown","children":[],"title":[["Plain","The criteria has changed and we now need to be able to pass in the initial value of the hook. This is where we'll start using "],["Link",{"url":["Page_ref","TDD"],"label":[["Plain",""]],"full_text":"[[TDD]]","metadata":""}],["Plain",". Let's add a new test that tests this criteria and update the code for our hook."]],"body":[],"content":"The criteria has changed and we now need to be able to pass in the initial value of the hook. This is where we'll start using [[TDD]]. Let's add a new test that tests this criteria and update the code for our hook."},{"id":"61915a86-9e5b-4057-a796-02de146209f0","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// useCustomHook.test.js","\n","\t ","\n","test('custom hook with custom initial value', () => {","\n"," // Pass in an initial value to the hook","\n"," const { result } = renderHook(() => useCustomHook('newInitial'))","\n","\t ","\n"," // Assert that the hook takes our passed value","\n"," expect(result.current).toEqual('newInitial')","\n","})","\n","\t ","\n","// Once we've confirmed that the test is indeed failing we can","\n","// make the necessary updates that will make it pass","\n","\t ","\n","// useCustomHook.js","\n","// Add the ability to pass in a value, but set the default value – which","\n","// is used if no value is passed – to what we had before 'Initial'.","\n","// This will make sure that our first test doesn't break","\n","export const useCustomHook = (initial = 'Initial') => {","\n"," const [state] = React.useState(initial)","\n","\t ","\n"," return state","\n","}","\n"],"language":"js","pos_meta":{"start_pos":11484,"end_pos":12298},"full_content":"```js\n// useCustomHook.test.js\n\ntest('custom hook with custom initial value', () => {\n // Pass in an initial value to the hook\n const { result } = renderHook(() => useCustomHook('newInitial'))\n\n // Assert that the hook takes our passed value\n expect(result.current).toEqual('newInitial')\n})\n\n// Once we've confirmed that the test is indeed failing we can\n// make the necessary updates that will make it pass\n\n// useCustomHook.js\n// Add the ability to pass in a value, but set the default value – which\n// is used if no value is passed – to what we had before 'Initial'.\n// This will make sure that our first test doesn't break\nexport const useCustomHook = (initial = 'Initial') => {\n const [state] = React.useState(initial)\n\n return state\n}\n```"}]],"content":"\t ```js\n// useCustomHook.test.js\n\ntest('custom hook with custom initial value', () => {\n // Pass in an initial value to the hook\n const { result } = renderHook(() => useCustomHook('newInitial'))\n\n // Assert that the hook takes our passed value\n expect(result.current).toEqual('newInitial')\n})\n\n// Once we've confirmed that the test is indeed failing we can\n// make the necessary updates that will make it pass\n\n// useCustomHook.js\n// Add the ability to pass in a value, but set the default value – which\n// is used if no value is passed – to what we had before 'Initial'.\n// This will make sure that our first test doesn't break\nexport const useCustomHook = (initial = 'Initial') => {\n const [state] = React.useState(initial)\n\n return state\n}\n```"},{"id":"61915a86-72e4-4cf8-90bc-18a14e31edae","format":"markdown","children":[],"title":[["Plain","Awesome, we've fulfilled the new demands for the custom hook. Unfortunately, the conditions changed again while we were fixing the last case. Now we also need to be able to update the value from outside the hook. For this we'll return the setter part of "],["Code","useState"],["Plain"," so that the consumer can update the internal value. Again we'll do this using TDD."]],"body":[],"content":"Awesome, we've fulfilled the new demands for the custom hook. Unfortunately, the conditions changed again while we were fixing the last case. Now we also need to be able to update the value from outside the hook. For this we'll return the setter part of `useState` so that the consumer can update the internal value. Again we'll do this using TDD."},{"id":"61915a86-b2aa-4c44-863e-a20df50cd22a","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// useCustomHook.test.js","\n","\t ","\n","// We now want to return two values from our hook, the current value and","\n","// a function to update the value with. Let's use the same style as useState","\n","// uses, an array with two values: [value, updateFunction]","\n","\t ","\n","test('custom hook return state', () => {","\n"," const { result } = renderHook(() => useCustomHook())","\n"," ","\n"," // The current value will now be the first item in an array","\n"," expect(result.current[0]).toEqual('Initial')","\n","})","\n","\t ","\n","test('custom hook with custom initial value', () => {","\n"," const { result } = renderHook(() => useCustomHook('newInitial'))","\n","\t ","\n"," // The current value will now be the first item in an array","\n"," expect(result.current[0]).toEqual('newInitial')","\n","})","\n","\t ","\n","test('custom hook with updater', () => {","\n"," const { result } = renderHook(() => useCustomHook())","\n","\t ","\n"," // The act utility is used to make the test run closer to how","\n"," // React actually calls it in the browser. The test passes without","\n"," // the act, but we would see an error in the test runner","\n"," act(() => {","\n"," // Call the second item of the returned array with our updated value","\n"," result.current[1]('newInitial')","\n"," })","\n","\t ","\n"," // Assert that our value is the updated one","\n"," expect(result.current[0]).toEqual('newInitial')","\n","})","\n","\t ","\n","// Finally once are tests are updated, we can rebuild the hook to make","\n","// all tests pass","\n","\t ","\n","// useCustomHook.js","\n","// Since we're now returning exactly the same as what useState returns","\n","// [state, setState], we can simply return the useState hook.","\n","export const useCustomHook = (initial = 'Initial') => React.useState(initial)","\n"],"language":"js","pos_meta":{"start_pos":12665,"end_pos":14319},"full_content":"```js\n// useCustomHook.test.js\n\n// We now want to return two values from our hook, the current value and\n// a function to update the value with. Let's use the same style as useState\n// uses, an array with two values: [value, updateFunction]\n\ntest('custom hook return state', () => {\n const { result } = renderHook(() => useCustomHook())\n \n // The current value will now be the first item in an array\n expect(result.current[0]).toEqual('Initial')\n})\n\ntest('custom hook with custom initial value', () => {\n const { result } = renderHook(() => useCustomHook('newInitial'))\n\n // The current value will now be the first item in an array\n expect(result.current[0]).toEqual('newInitial')\n})\n\ntest('custom hook with updater', () => {\n const { result } = renderHook(() => useCustomHook())\n\n // The act utility is used to make the test run closer to how\n // React actually calls it in the browser. The test passes without\n // the act, but we would see an error in the test runner\n act(() => {\n // Call the second item of the returned array with our updated value\n result.current[1]('newInitial')\n })\n\n // Assert that our value is the updated one\n expect(result.current[0]).toEqual('newInitial')\n})\n\n// Finally once are tests are updated, we can rebuild the hook to make\n// all tests pass\n\n// useCustomHook.js\n// Since we're now returning exactly the same as what useState returns\n// [state, setState], we can simply return the useState hook.\nexport const useCustomHook = (initial = 'Initial') => React.useState(initial)\n```"}]],"content":"\t ```js\n// useCustomHook.test.js\n\n// We now want to return two values from our hook, the current value and\n// a function to update the value with. Let's use the same style as useState\n// uses, an array with two values: [value, updateFunction]\n\ntest('custom hook return state', () => {\n const { result } = renderHook(() => useCustomHook())\n \n // The current value will now be the first item in an array\n expect(result.current[0]).toEqual('Initial')\n})\n\ntest('custom hook with custom initial value', () => {\n const { result } = renderHook(() => useCustomHook('newInitial'))\n\n // The current value will now be the first item in an array\n expect(result.current[0]).toEqual('newInitial')\n})\n\ntest('custom hook with updater', () => {\n const { result } = renderHook(() => useCustomHook())\n\n // The act utility is used to make the test run closer to how\n // React actually calls it in the browser. The test passes without\n // the act, but we would see an error in the test runner\n act(() => {\n // Call the second item of the returned array with our updated value\n result.current[1]('newInitial')\n })\n\n // Assert that our value is the updated one\n expect(result.current[0]).toEqual('newInitial')\n})\n\n// Finally once are tests are updated, we can rebuild the hook to make\n// all tests pass\n\n// useCustomHook.js\n// Since we're now returning exactly the same as what useState returns\n// [state, setState], we can simply return the useState hook.\nexport const useCustomHook = (initial = 'Initial') => React.useState(initial)\n```"},{"id":"61915a86-1948-40c7-b286-047dc2f1171d","format":"markdown","children":[],"title":[["Plain","This was the complete code of our final scenario and the competed code is available in "],["Link",{"url":["Complex",{"protocol":"https","link":"github.com/believer/frontend-testing-workshop/tree/3-hooks-complete"}],"label":[["Code","3-hooks-complete"]],"full_text":"[`3-hooks-complete`](https://github.com/believer/frontend-testing-workshop/tree/3-hooks-complete)","metadata":""}],["Plain"," branch."]],"body":[],"content":"This was the complete code of our final scenario and the competed code is available in [`3-hooks-complete`](https://github.com/believer/frontend-testing-workshop/tree/3-hooks-complete) branch."}],"title":[["Plain","Custom hooks"]],"body":[],"content":"### Custom hooks"}]},{"id":"61915a86-b014-40d5-90d7-a770ba494203","page-name":"Ryan Florence","properties":{"public":true},"children":[{"id":"61915a86-7097-4723-884b-eb0059be46fa","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-b6af-41dd-b75f-1e0e60090c9a","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-84a7-42ce-a6b4-14f09885b2fe","page-name":"TDD","children":[{"id":"61915a86-d6c0-4c64-bfb3-766aaaa4746e","format":"markdown","children":[],"title":[["Plain","Test-driven development"]],"body":[],"content":"Test-driven development"}]},{"id":"61915a86-dae0-4844-807c-06041fb7fb10","page-name":"Testing Library","properties":{"public":true},"children":[{"id":"61915a86-70a6-4ed7-86f7-8730336fca7e","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-de88-475a-97fb-4186cdcae307","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-4c91-4bb3-bc5b-96a18365743d","page-name":"Technical debt","properties":{"public":true},"children":[{"id":"61915a86-de60-4d44-835a-03a247901146","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-a187-47c0-ba7b-c29c2b75103a","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-a76c-4f06-a408-034db3dcf78e","page-name":"Hemnet","properties":{"public":true},"children":[{"id":"61915a86-fed1-4f9e-955f-ae070e7e8323","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-9bb1-48e9-8bbd-8af9464c758c","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-2ce4-4987-950b-9a9c6237b63e","page-name":"Grace Hopper","properties":{"public":true},"children":[{"id":"61915a86-8c4c-4bd1-a027-a93282151ad3","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-5cff-4429-acce-981f371fdd1c","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-dbd5-4c8d-a8d2-e94235ecaf8c","page-name":"Etymology","properties":{"public":true},"children":[{"id":"61915a86-f4dc-41cd-b80f-1a2b5dce706a","properties":{"public":true},"format":"markdown","children":[],"content":"public:: true\n"}]},{"id":"61915a86-0e7a-499d-bf1c-96b6344ff64a","page-name":"Describe what you're doing before doing it","properties":{"tags":["Development","Learning","Teaching"],"pid":210830192911},"children":[{"id":"61915a9b-050d-4f69-97f3-d1342b266627","properties":{"tags":["Development","Learning","Teaching"],"pid":210830192911},"format":"markdown","children":[],"content":"tags:: Development, Learning, Teaching,\npid:: 210830192911"},{"id":"61915a86-0cb8-45f9-b6de-2859d2f5bc4c","properties":{},"format":"markdown","children":[],"title":[["Plain","Describe what you're going to do and why before "],["Emphasis",[["Italic"],[["Plain","actually"]]]],["Plain"," doing it when you're teaching something to someone."]],"body":[],"content":"Describe what you're going to do and why before _actually_ doing it when you're teaching something to someone."},{"id":"61915a86-7269-467b-b7ac-833bd0b8e429","format":"markdown","children":[{"id":"61915a86-543e-4906-ba06-fcb77f3fe2df","format":"markdown","children":[],"title":[["Plain","If they have any objections or questions, they'll also get the time to ask them."]],"body":[],"content":"If they have any objections or questions, they'll also get the time to ask them."}],"title":[["Plain","The student will have a harder time following what you're doing if the code you're writing just \"magically appears\". This becomes even more relevant depending on the student's level of knowledge."]],"body":[],"content":"The student will have a harder time following what you're doing if the code you're writing just \"magically appears\". This becomes even more relevant depending on the student's level of knowledge."},{"id":"61915a86-1081-49db-8d22-94f057e2c7cf","format":"markdown","children":[],"title":[["Plain","By putting words to what you're doing you'll also get to think it through. "],["Link",{"url":["Page_ref","Rubber ducking"],"label":[["Plain",""]],"full_text":"[[Rubber ducking]]","metadata":""}]],"body":[],"content":"By putting words to what you're doing you'll also get to think it through. [[Rubber ducking]]"},{"id":"61915a86-9912-4012-b591-51e08660d4ce","format":"markdown","children":[],"title":[["Plain","This might be even more helpful when working remotely as you don't get the same connection as when you're sitting by the same computer."]],"body":[],"content":"This might be even more helpful when working remotely as you don't get the same connection as when you're sitting by the same computer."},{"id":"61915a86-cd3e-4472-9e59-697548348b0a","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-7cae-4404-805f-e495856b43f5","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","React Podcast"],"label":[["Plain",""]],"full_text":"[[React Podcast]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2020-12-17"],"label":[["Plain",""]],"full_text":"[[2020-12-17]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","123: Cassidy Williams on Dreams and Disasters in 2020"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"spec.fm/podcasts/reactpodcast/XHRPTLZZ"}],"label":[["Plain","Link"]],"full_text":"[Link](https://spec.fm/podcasts/reactpodcast/XHRPTLZZ)","metadata":""}]],"body":[],"content":"[[React Podcast]]. ([[2020-12-17]]). _123: Cassidy Williams on Dreams and Disasters in 2020_. [Link](https://spec.fm/podcasts/reactpodcast/XHRPTLZZ)"}]},{"id":"61915a86-6b0c-4d1f-b2d5-37d1630f0af0","page-name":"JavaScript","properties":{"public":true},"children":[{"id":"61915a86-b528-4bcf-8e28-6adaa0802f1a","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-8beb-48f4-8fd9-ec273881bd66","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-63ab-46ab-b9af-cad6d7232d11","page-name":"Write useful error messages","properties":{"tags":["Errors","Writing"],"pid":210609111151},"children":[{"id":"61915a86-be62-4cb4-9613-018a0d605e09","properties":{"tags":["Errors","Writing"],"pid":210609111151},"format":"markdown","children":[],"content":"tags:: Errors, Writing,\npid:: 210609111151"},{"id":"61915a86-e93e-4192-a2e8-d906b3d73019","format":"markdown","children":[],"title":[["Plain","Inform your users what is happening by writing good and useful error messages. This will hopefully lead to few support errands in the long run as the user can understand what went wrong."]],"body":[],"content":"Inform your users what is happening by writing good and useful error messages. This will hopefully lead to few support errands in the long run as the user can understand what went wrong."},{"id":"61915a86-89fc-4e13-847c-5d20bfdf0ddd","format":"markdown","children":[{"id":"61915a86-a2e9-4a97-a578-634207333aa2","format":"markdown","children":[],"title":[["Plain","Write using plain words. Avoid technical jargon and error codes"]],"body":[],"content":"Write using plain words. Avoid technical jargon and error codes"},{"id":"61915a86-2994-41af-95e8-866932aed0a4","format":"markdown","children":[],"title":[["Plain","Tell the user exactly what went wrong. "],["Emphasis",[["Bold"],[["Plain","What"]]]],["Plain"," happened, and "],["Emphasis",[["Bold"],[["Plain","why"]]]],["Plain","?"]],"body":[],"content":"Tell the user exactly what went wrong. **What** happened, and **why**?"},{"id":"61915a86-167f-40b9-9119-31ab992cd8b9","format":"markdown","children":[],"title":[["Plain","Tell the user how the problem can be fixed. "],["Emphasis",[["Bold"],[["Plain","When"]]]],["Plain"," will it be fixed and "],["Emphasis",[["Bold"],[["Plain","How"]]]],["Plain"," can the user respond to the error?"]],"body":[],"content":"Tell the user how the problem can be fixed. **When** will it be fixed and **How** can the user respond to the error?"}],"title":[["Plain","The "],["Link",{"url":["Page_ref","Nielsen Norman Group"],"label":[["Plain",""]],"full_text":"[[Nielsen Norman Group]]","metadata":""}],["Plain"," "],["Link",{"url":["Complex",{"protocol":"https","link":"www.nngroup.com/articles/improving-dreaded-404-error-message/"}],"label":[["Plain","wrote about it"]],"full_text":"[wrote about it](https://www.nngroup.com/articles/improving-dreaded-404-error-message/)","metadata":""}],["Plain"," in 1998 and summarized it in these three guiding principles:"]],"body":[],"content":"The [[Nielsen Norman Group]] [wrote about it](https://www.nngroup.com/articles/improving-dreaded-404-error-message/) in 1998 and summarized it in these three guiding principles:"},{"id":"61915a86-b509-43ca-8939-0971594bfdbd","properties":{"later":1623229872696},"format":"markdown","children":[],"title":[["Plain","Use "],["Emphasis",[["Italic"],[["Plain","we"]]]],["Plain"," when the error is on the developer's side, e.g. \"We are down for maintenance\". Use "],["Emphasis",[["Italic"],[["Plain","you"]]]],["Plain"," when the error is on the user's side, e.g. \"Access Denied. You don not have permission to view this page\""]],"body":[],"content":"Use _we_ when the error is on the developer's side, e.g. \"We are down for maintenance\". Use _you_ when the error is on the user's side, e.g. \"Access Denied. You don not have permission to view this page\"\nlater:: 1623229872696"},{"id":"61915a86-68e2-40e1-964f-7776d71f7641","format":"markdown","children":[],"title":[["Plain","Use words like \"Page not found. The URL might be incorrect.\" instead of writing \"404 Not found\""]],"body":[],"content":"Use words like \"Page not found. The URL might be incorrect.\" instead of writing \"404 Not found\""},{"id":"61915a86-e753-4de5-93f8-88b09649d576","format":"markdown","children":[],"title":[["Plain","We don't always know how long an error will persist. Add links to a status page (if available), to a "],["Link",{"url":["Page_ref","Twitter"],"label":[["Plain",""]],"full_text":"[[Twitter]]","metadata":""}],["Plain"," acccount, or another way for the user to get in touch if they need to."]],"body":[],"content":"We don't always know how long an error will persist. Add links to a status page (if available), to a [[Twitter]] acccount, or another way for the user to get in touch if they need to."},{"id":"61915a86-3c78-46e3-b515-96a1c5a63eb2","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-43ee-490e-b31f-e4e75b927324","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Max Rozen"],"label":[["Plain",""]],"full_text":"[[Max Rozen]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-06-08"],"label":[["Plain",""]],"full_text":"[[2021-06-08]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","What the Fastly outage can teach us about writing error messages"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"onlineornot.com/what-fastly-outage-can-teach-about-writing-error-messages"}],"label":[["Plain","Link"]],"full_text":"[Link](https://onlineornot.com/what-fastly-outage-can-teach-about-writing-error-messages)","metadata":""}]],"body":[],"content":"[[Max Rozen]]. ([[2021-06-08]]). _What the Fastly outage can teach us about writing error messages_. [Link](https://onlineornot.com/what-fastly-outage-can-teach-about-writing-error-messages)"}]},{"id":"61915a86-1044-43f1-a20c-00878c75547f","page-name":"2021-06-08","properties":{"public":true},"children":[{"id":"61915a86-08aa-49f5-98bf-78152055e991","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-9ad5-43aa-9f24-97d0b7327d0d","format":"markdown","children":[],"title":[["Plain","Write out all the test cases – that you can think of – as TODOs before you start writing the code. "],["Link",{"url":["Page_ref","Jest"],"label":[["Plain",""]],"full_text":"[[Jest]]","metadata":""}],["Plain"," will display these tests as a separate metric in the interactive runner and in the test summary. It's as simple as using "],["Code","test.todo('description')"],["Plain"," "],["Tag",[["Link",{"url":["Page_ref","Testing"],"label":[["Plain",""]],"full_text":"[[Testing]]","metadata":""}]]]],"body":[],"content":"Write out all the test cases – that you can think of – as TODOs before you start writing the code. [[Jest]] will display these tests as a separate metric in the interactive runner and in the test summary. It's as simple as using `test.todo('description')` #[[Testing]]"}]},{"id":"61915a86-adc8-41b5-aa8f-59f6eb6ff184","page-name":"Index signature","properties":{"public":true},"children":[{"id":"61915a86-3022-4cc4-a220-509878bee883","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-7cde-4115-9fa5-4f6c97954138","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures"}],"label":[["Plain","Documentation"]],"full_text":"[Documentation](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures)","metadata":""}]],"body":[],"content":"[Documentation](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures)"}]},{"id":"61915a86-c882-4f79-ab31-b4046cb98ac2","page-name":"Write great alt texts for images","properties":{"tags":["Accessibility","Development"],"pid":210803224234},"children":[{"id":"61915abe-5596-4e0b-a3ab-990031900dd3","properties":{"tags":["Accessibility","Development"],"pid":210803224234},"format":"markdown","children":[],"content":"tags:: Accessibility, Development,\npid:: 210803224234"},{"id":"61915a86-798f-49dc-9a8d-762f607cd97d","properties":{},"format":"markdown","children":[{"id":"61915a86-e741-4ae1-95c2-210f54b52ede","format":"markdown","children":[],"title":[["Plain","Alt-texts aren't only beneficial for screen readers. The text is also displayed when an image isn't able to load. This might happen due to an error or if the user has turned off image loading."]],"body":[],"content":"Alt-texts aren't only beneficial for screen readers. The text is also displayed when an image isn't able to load. This might happen due to an error or if the user has turned off image loading."},{"id":"61915a86-0559-4f47-88f6-1e759b80a6ed","format":"markdown","children":[],"title":[["Plain","If done well, good alt-texts might also improve your "],["Link",{"url":["Page_ref","SEO"],"label":[["Plain",""]],"full_text":"[[SEO]]","metadata":""}],["Plain"," score."]],"body":[],"content":"If done well, good alt-texts might also improve your [[SEO]] score."}],"title":[["Plain","A "],["Link",{"url":["Complex",{"protocol":"https","link":"webaim.org/projects/million/"}],"label":[["Plain","study by WebAIM"]],"full_text":"[study by WebAIM](https://webaim.org/projects/million/)","metadata":""}],["Plain"," from 2019 found that missing alt-texts is the second most common failure of "],["Link",{"url":["Page_ref","Accessibility"],"label":[["Plain",""]],"full_text":"[[Accessibility]]","metadata":""}],["Plain"," on the web. If you don't provide an alt-text the screen reader would say \"Image\" or on some devices it might read the filename."]],"body":[],"content":"A [study by WebAIM](https://webaim.org/projects/million/) from 2019 found that missing alt-texts is the second most common failure of [[Accessibility]] on the web. If you don't provide an alt-text the screen reader would say \"Image\" or on some devices it might read the filename."},{"id":"61915a86-aa98-4e99-9049-48642dc81972","format":"markdown","children":[{"id":"61915a86-b18a-447a-9807-7912c15e6aa1","format":"markdown","children":[],"title":[["Emphasis",[["Bold"],[["Plain","Imagine that you're describing the image to a person over the phone"]]]]],"body":[],"content":"**Imagine that you're describing the image to a person over the phone**"},{"id":"61915a86-523c-4d7d-99a6-a6b98d32e53c","format":"markdown","children":[],"title":[["Emphasis",[["Bold"],[["Plain","The recommendation is 125 characters and one sentence or two should be enough."]]]]],"body":[],"content":"**The recommendation is 125 characters and one sentence or two should be enough.**"},{"id":"61915a86-d703-4ee0-bdcd-a6ffde39bc4b","format":"markdown","children":[],"title":[["Plain","Think about context related to the topic you want to describe. e.g. "],["Code","alt=\"Business school professor pointing to a student's computer screen\""],["Plain"," instead of "],["Code","alt=\"Woman pointing to a person's computer screen\""]],"body":[],"content":"Think about context related to the topic you want to describe. e.g. `alt=\"Business school professor pointing to a student's computer screen\"` instead of `alt=\"Woman pointing to a person's computer screen\"`"}],"title":[["Plain","Be specific and concise. Think about what's relevant in the picture, for instance if it's important to convey what color something is or if the image contains a specific person. "],["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}],["Plain","."]],"body":[],"content":"Be specific and concise. Think about what's relevant in the picture, for instance if it's important to convey what color something is or if the image contains a specific person. [[Explain in plain words]]."},{"id":"61915a86-e9f9-46bd-98c3-9edf028bd96c","format":"markdown","children":[],"title":[["Plain","Use an empty value, "],["Code","alt=\"\""],["Plain",", if an image is decorative or does not contain any valuable information."]],"body":[],"content":"Use an empty value, `alt=\"\"`, if an image is decorative or does not contain any valuable information."},{"id":"61915a86-ebe3-490b-8eaf-c061bd77bbef","format":"markdown","children":[],"title":[["Plain","Don't add \"A photo of...\" or \"An image of...\"."]],"body":[],"content":"Don't add \"A photo of...\" or \"An image of...\"."},{"id":"61915a86-bc0d-4241-a982-cd73bb0ae0b3","format":"markdown","children":[],"title":[["Plain","If an alt-text needs to be very long or is complex you might need to include the text somewhere else on the page. "],["Link",{"url":["Complex",{"protocol":"https","link":"accessibility.psu.edu/images/"}],"label":[["Plain","Here are some guidelines for complex images"]],"full_text":"[Here are some guidelines for complex images](https://accessibility.psu.edu/images/)","metadata":""}]],"body":[],"content":"If an alt-text needs to be very long or is complex you might need to include the text somewhere else on the page. [Here are some guidelines for complex images](https://accessibility.psu.edu/images/)"},{"id":"61915a86-ebd8-4750-932e-8f4869cdcfa2","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-2b33-4932-b01d-2e694554c67b","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","The Big Hack"],"label":[["Plain",""]],"full_text":"[[The Big Hack]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2019-10-07"],"label":[["Plain",""]],"full_text":"[[2019-10-07]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","How to write better alt-text descriptions for accessibility"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/"}],"label":[["Plain","https://bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/"]],"full_text":"https://bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/","metadata":""}]],"body":[],"content":"[[The Big Hack]]. ([[2019-10-07]]). _How to write better alt-text descriptions for accessibility_. https://bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/"},{"id":"61915a86-765e-44e7-bd69-5edc3d8987f9","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Braden Becker"],"label":[["Plain",""]],"full_text":"[[Braden Becker]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-07-12"],"label":[["Plain",""]],"full_text":"[[2021-07-12]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","Image Alt Text: What It Is, How to Write It, and Why It Matters to SEO"]]]],["Plain"," "],["Link",{"url":["Complex",{"protocol":"https","link":"blog.hubspot.com/marketing/image-alt-text"}],"label":[["Plain","https://blog.hubspot.com/marketing/image-alt-text"]],"full_text":"https://blog.hubspot.com/marketing/image-alt-text","metadata":""}]],"body":[],"content":"[[Braden Becker]]. ([[2021-07-12]]). _Image Alt Text: What It Is, How to Write It, and Why It Matters to SEO_ https://blog.hubspot.com/marketing/image-alt-text"}]},{"id":"61915a86-3c17-4052-b3a9-ceae174a0cd0","page-name":"2021-08-30","children":[{"id":"61915a86-51f7-4a28-9f8a-7bea14976f79","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Describe what you're doing before doing it"],"label":[["Plain",""]],"full_text":"[[Describe what you're doing before doing it]]","metadata":""}]],"body":[],"content":"[[Describe what you're doing before doing it]]"}]},{"id":"61915a86-f68a-405a-a57a-3fb216d11f8b","page-name":"The Etymology of Programming","properties":{"tags":["Development"],"pid":210622073324},"children":[{"id":"61915b11-4645-4f65-be52-9012bdf41d0a","properties":{"tags":["Development"],"pid":210622073324},"format":"markdown","children":[],"content":"tags:: Development,\npid:: 210622073324"},{"id":"61915a86-f76a-4755-b17c-8ddd48c1ac08","properties":{},"format":"markdown","children":[],"title":[["Plain","In the 1940s a technical team at "],["Link",{"url":["Page_ref","Harvard University"],"label":[["Plain",""]],"full_text":"[[Harvard University]]","metadata":""}],["Plain"," found a moth in one of their machines that caused it to not function properly. "],["Link",{"url":["Page_ref","Grace Hopper"],"label":[["Plain",""]],"full_text":"[[Grace Hopper]]","metadata":""}],["Plain",", who was part of the team, taped the moth to a report with the text \"First actual case of bug being found\". From here on the term "],["Emphasis",[["Bold"],[["Plain","bug"]]]],["Plain"," became popularized as an error."]],"body":[],"content":"In the 1940s a technical team at [[Harvard University]] found a moth in one of their machines that caused it to not function properly. [[Grace Hopper]], who was part of the team, taped the moth to a report with the text \"First actual case of bug being found\". From here on the term **bug** became popularized as an error."},{"id":"61915a86-b9a7-4c77-bb44-08c71fda85ba","format":"markdown","children":[],"title":[["Emphasis",[["Bold"],[["Plain","Debugging"]]]],["Plain"," literally meant to remove any bugs from the machinery. This has sparked some discussions since it can imply that it's something other than developer error that causes the issue."]],"body":[],"content":"**Debugging** literally meant to remove any bugs from the machinery. This has sparked some discussions since it can imply that it's something other than developer error that causes the issue."},{"id":"61915a86-125c-45ad-9142-fdd39accd4f2","format":"markdown","children":[{"id":"61915a86-e4aa-40a9-9632-f161fb7ea5f0","format":"markdown","children":[],"title":[["Plain","The origin of this touches on the same category as master/slave and whitelist/blacklist. Which we are trying to move away from."]],"body":[],"content":"The origin of this touches on the same category as master/slave and whitelist/blacklist. Which we are trying to move away from."}],"title":[["Emphasis",[["Bold"],[["Plain","foobar"]]]],["Plain"," comes from the military term \"FUBAR\", \"Fucked Up Beyond All Recognition\". Instead we should "],["Link",{"url":["Page_ref","Always use real variable names in examples"],"label":[["Plain",""]],"full_text":"[[Always use real variable names in examples]]","metadata":""}]],"body":[],"content":"**foobar** comes from the military term \"FUBAR\", \"Fucked Up Beyond All Recognition\". Instead we should [[Always use real variable names in examples]]"},{"id":"61915a86-c8b8-4fb7-9a37-974a9ab80341","format":"markdown","children":[],"title":[["Plain","The "],["Emphasis",[["Bold"],[["Plain","shell"]]]],["Plain"," (terminal) is a metaphor for a nut. We interact with the outer layer, but don't have direct access to \"the inner seed\", the "],["Link",{"url":["Page_ref","Kernel"],"label":[["Plain",""]],"full_text":"[[Kernel]]","metadata":""}],["Plain","."]],"body":[],"content":"The **shell** (terminal) is a metaphor for a nut. We interact with the outer layer, but don't have direct access to \"the inner seed\", the [[Kernel]]."},{"id":"61915a86-4c63-4646-81a6-5a5382e2b2df","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-1603-4a22-8bc9-f9180a1f123c","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Brittany Storoz"],"label":[["Plain",""]],"full_text":"[[Brittany Storoz]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2018-06-26"],"label":[["Plain",""]],"full_text":"[[2018-06-26]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"The Etymology of Programming\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"youtu.be/2KTK2qD4-gs"}],"label":[["Plain","https://youtu.be/2KTK2qD4-gs"]],"full_text":"https://youtu.be/2KTK2qD4-gs","metadata":""}]],"body":[],"content":"[[Brittany Storoz]]. ([[2018-06-26]]). _\"The Etymology of Programming\"_. https://youtu.be/2KTK2qD4-gs"}]},{"id":"6191967f-0842-4143-b1b0-fbc43e71b997","page-name":"2021-11-15","format":"markdown","children":[{"id":"6191967f-d49f-4c72-905c-e77411ceda4f","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Recommended way of importing React"],"label":[["Plain",""]],"full_text":"[[Recommended way of importing React]]","metadata":""}]],"body":[],"content":"[[Recommended way of importing React]]"}]},{"id":"61915a86-306a-4919-9c8c-4efa5ae80de3","page-name":"SEO","properties":{"public":true},"children":[{"id":"61915a86-cf5e-4278-afbe-f40d4d6464e3","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-50d0-4265-b7ce-769fbe50d492","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-cba6-4827-bbb9-e2546d5fc568","page-name":"Twitter","properties":{"public":true},"children":[{"id":"61915a86-535f-44ad-b4fa-dd9bca328d4e","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-98dc-4c36-bfe7-27852e32cdcd","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61968d8c-e594-4dec-b449-e7a26b8a8c48","page-name":"People cost more than their tools","properties":{"tags":["Development"],"pid":211116192906},"children":[{"id":"61968d8c-516e-4454-ba86-29d6813ac2bf","properties":{"tags":["Development"],"pid":211116192906},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"tags:: Development,\npid:: 211116192906\n\n"},{"id":"61968d8c-7a97-4926-b534-17007e969a10","format":"markdown","children":[],"title":[["Plain","Invest in the tools your developers use. That includes their hardware, like what computers they are using, software that make menial tasks faster as well as making "],["Link",{"url":["Page_ref","CI"],"label":[["Plain",""]],"full_text":"[[CI]]","metadata":""}],["Plain"," pipelines as efficient as possible. The "],["Link",{"url":["Complex",{"protocol":"https","link":"turborepo.com/roi-calculator"}],"label":[["Plain","ROI"]],"full_text":"[ROI](https://turborepo.com/roi-calculator)","metadata":""}],["Plain"," might be quicker than you think and your developers will most likely be happier."]],"body":[],"content":"Invest in the tools your developers use. That includes their hardware, like what computers they are using, software that make menial tasks faster as well as making [[CI]] pipelines as efficient as possible. The [ROI](https://turborepo.com/roi-calculator) might be quicker than you think and your developers will most likely be happier."},{"id":"61968d8c-2ee7-419e-ab62-0751be1a33b1","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61968d8c-6ef8-48e0-9b5d-6a545ed6a4d3","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Jared Palmer"],"label":[["Plain",""]],"full_text":"[[Jared Palmer]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-04"],"label":[["Plain",""]],"full_text":"[[2021-11-04]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/jaredpalmer/status/1456261694074736671"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/jaredpalmer/status/1456261694074736671)","metadata":""}]],"body":[],"content":"[[Jared Palmer]]. [[2021-11-04]]. [Tweet](https://twitter.com/jaredpalmer/status/1456261694074736671)"},{"id":"61968d8c-dc68-48bd-9e43-2dc0b52d1f32","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Joe Szumski"],"label":[["Plain",""]],"full_text":"[[Joe Szumski]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-05"],"label":[["Plain",""]],"full_text":"[[2021-11-05]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/jszumski/status/1456715133615579140"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/jszumski/status/1456715133615579140)","metadata":""}]],"body":[],"content":"[[Joe Szumski]]. [[2021-11-05]]. [Tweet](https://twitter.com/jszumski/status/1456715133615579140)"}]},{"id":"61915a86-9da9-4908-83aa-4627c2ee9777","page-name":"What's new in React 18","children":[{"id":"61915a86-8728-4733-89e1-9dd358b72cfb","heading-level":2,"format":"markdown","children":[{"id":"61915a86-284b-481c-bf42-f5532b08b7e8","format":"markdown","children":[],"title":[["Plain","If two "],["Code","setState"],["Plain"," hooks are called inside a function, they are batched together and only perform one re-render. However, if we were to use these same hooks inside any other context, like a "],["Link",{"url":["Page_ref","Promise"],"label":[["Plain",""]],"full_text":"[[Promise]]","metadata":""}],["Plain",", an event listener or a "],["Code","setTimeout"],["Plain"," you would get two renders. It was possible to get the same behavior using "],["Code","unstable_batchedUpdates"],["Plain",", but as of "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," 18 it's now turned on by default."]],"body":[],"content":"If two `setState` hooks are called inside a function, they are batched together and only perform one re-render. However, if we were to use these same hooks inside any other context, like a [[Promise]], an event listener or a `setTimeout` you would get two renders. It was possible to get the same behavior using `unstable_batchedUpdates`, but as of [[React]] 18 it's now turned on by default."},{"id":"61915a86-2a5e-4889-a682-64b6f5ac6486","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["const handleClick = () => {","\n"," setCount(count + 1)","\n"," setClicked(true)","\n","}","\n","const [count, setCount] = React.useState(0)","\n","const [clicked, setClicked] = React.useState(false)","\n","\t ","\n","// These calls are batched together and only perform","\n","// on re-render. This works before React 18","\n","const handleClick = () => {","\n"," setCount(count + 1)","\n"," setClicked(true)","\n","}","\n","\t ","\n","// Before React 18, all three of the following cases would perform","\n","// two re-renders. ","\n","fetch('...').then(() => {","\n"," setCount(count + 1)","\n"," setClicked(true)","\n","})","\n","\t ","\n","element.addEventlistener('click', () => {","\n"," setCount(count + 1)","\n"," setClicked(true) ","\n","})","\n","\t ","\n","setTimeout(() => {","\n"," setCount(count + 1)","\n"," setClicked(true) ","\n","}, 1000)","\n","\t ","\n","// If you really want the updates to not be batched you can use","\n","// the flushSync utility from react-dom","\n","import { flushSync } from 'react-dom'","\n","\t ","\n","const handleClick = () => {","\n"," flushSync(() => {","\n"," setCount(count + 1)","\n"," })","\n"," ","\n"," flushSync(() => {","\n"," setClicked(true)","\n"," })","\n","}","\n"],"language":"js","pos_meta":{"start_pos":430,"end_pos":1492},"full_content":"```js\nconst handleClick = () => {\n setCount(count + 1)\n setClicked(true)\n}\nconst [count, setCount] = React.useState(0)\nconst [clicked, setClicked] = React.useState(false)\n\n// These calls are batched together and only perform\n// on re-render. This works before React 18\nconst handleClick = () => {\n setCount(count + 1)\n setClicked(true)\n}\n\n// Before React 18, all three of the following cases would perform\n// two re-renders. \nfetch('...').then(() => {\n setCount(count + 1)\n setClicked(true)\n})\n\nelement.addEventlistener('click', () => {\n setCount(count + 1)\n setClicked(true) \n})\n\nsetTimeout(() => {\n setCount(count + 1)\n setClicked(true) \n}, 1000)\n\n// If you really want the updates to not be batched you can use\n// the flushSync utility from react-dom\nimport { flushSync } from 'react-dom'\n\nconst handleClick = () => {\n flushSync(() => {\n setCount(count + 1)\n })\n \n flushSync(() => {\n setClicked(true)\n })\n}\n```"}]],"content":"\t ```js\nconst handleClick = () => {\n setCount(count + 1)\n setClicked(true)\n}\nconst [count, setCount] = React.useState(0)\nconst [clicked, setClicked] = React.useState(false)\n\n// These calls are batched together and only perform\n// on re-render. This works before React 18\nconst handleClick = () => {\n setCount(count + 1)\n setClicked(true)\n}\n\n// Before React 18, all three of the following cases would perform\n// two re-renders. \nfetch('...').then(() => {\n setCount(count + 1)\n setClicked(true)\n})\n\nelement.addEventlistener('click', () => {\n setCount(count + 1)\n setClicked(true) \n})\n\nsetTimeout(() => {\n setCount(count + 1)\n setClicked(true) \n}, 1000)\n\n// If you really want the updates to not be batched you can use\n// the flushSync utility from react-dom\nimport { flushSync } from 'react-dom'\n\nconst handleClick = () => {\n flushSync(() => {\n setCount(count + 1)\n })\n \n flushSync(() => {\n setClicked(true)\n })\n}\n```"}],"title":[["Plain","Automatic batching"]],"body":[],"content":"## Automatic batching"},{"id":"61915a86-f2ee-4a78-8102-cf0b95dc48ab","heading-level":2,"format":"markdown","children":[{"id":"61915a86-438b-4620-bf9e-1527020c51fc","format":"markdown","children":[],"title":[["Plain","Transitions tell "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," which updates are urgent and which are not. A good example would be an input field that filters out a list. Entering an input would be marked as urgent and the filtering of the list is secondary. If the list is in the process of filtering, typing in the input would "],["Emphasis",[["Bold"],[["Plain","interrupt"]]]],["Plain"," the filtering and discard the result."]],"body":[],"content":"Transitions tell [[React]] which updates are urgent and which are not. A good example would be an input field that filters out a list. Entering an input would be marked as urgent and the filtering of the list is secondary. If the list is in the process of filtering, typing in the input would **interrupt** the filtering and discard the result."},{"id":"61915a86-213e-4a45-84d3-cc31567d4e94","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["import { startTransition } from 'react'","\n","\t ","\n","// Urgent: Show what was typed","\n","setInputValue(value)","\n","\t ","\n","startTransition(() => {","\n"," // Secondary: Show results","\n"," setSearchQuery(value)","\n","})","\n"],"language":"js","pos_meta":{"start_pos":1871,"end_pos":2075},"full_content":"```js\nimport { startTransition } from 'react'\n\n// Urgent: Show what was typed\nsetInputValue(value)\n\nstartTransition(() => {\n // Secondary: Show results\n setSearchQuery(value)\n})\n```"}]],"content":"\t ```js\nimport { startTransition } from 'react'\n\n// Urgent: Show what was typed\nsetInputValue(value)\n\nstartTransition(() => {\n // Secondary: Show results\n setSearchQuery(value)\n})\n```"}],"title":[["Plain","Transitions"]],"body":[],"content":"## Transitions"},{"id":"61915a86-85ec-4b22-bf72-95bc7d7f8125","heading-level":2,"format":"markdown","children":[{"id":"61915a86-7213-4bc4-984f-1021c01fb411","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," 18 supports two features for better "],["Link",{"url":["Page_ref","SSR"],"label":[["Plain",""]],"full_text":"[[SSR]]","metadata":""}],["Plain",": streaming HTML and selective hydration. "],["Emphasis",[["Bold"],[["Plain","Streaming HTML"]]]],["Plain"," means that you can send some pieces of you UI directly and have it wait for other parts that might take longer to load. This works by using the "],["Code","<Suspense>"],["Plain"," component."]],"body":[],"content":"[[React]] 18 supports two features for better [[SSR]]: streaming HTML and selective hydration. **Streaming HTML** means that you can send some pieces of you UI directly and have it wait for other parts that might take longer to load. This works by using the `<Suspense>` component."},{"id":"61915a86-d5df-472e-ac9c-3d075199907e","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// We render the important parts straight away","\n","<Navigation />","\n","<Article />","\n","// The comments can take longer to load and aren't as important as the","\n","// article. Therefore, we can make the UI wait for this","\n","<Suspense fallback={<Spinner />}>","\n"," <Comments />","\n","</Suspense>","\n"],"language":"jsx","pos_meta":{"start_pos":2397,"end_pos":2686},"full_content":"```jsx\n// We render the important parts straight away\n<Navigation />\n<Article />\n// The comments can take longer to load and aren't as important as the\n// article. Therefore, we can make the UI wait for this\n<Suspense fallback={<Spinner />}>\n <Comments />\n</Suspense>\n```"}]],"content":"\t ```jsx\n// We render the important parts straight away\n<Navigation />\n<Article />\n// The comments can take longer to load and aren't as important as the\n// article. Therefore, we can make the UI wait for this\n<Suspense fallback={<Spinner />}>\n <Comments />\n</Suspense>\n```"},{"id":"61915a86-e343-49ca-9222-7b20960c391d","format":"markdown","children":[],"title":[["Plain","Hydration is the final part of making you page interactive when using SSR. It happens after the "],["Link",{"url":["Page_ref","JavaScript"],"label":[["Plain",""]],"full_text":"[[JavaScript]]","metadata":""}],["Plain"," has been fetched and loaded. Previously, this part would block the pattern above, but with "],["Emphasis",[["Bold"],[["Plain","selective hydration"]]]],["Plain"," each part can start hydrating whenever that part is ready. If the user starts interacting with a component before it's been fully hydrated, React will "],["Emphasis",[["Bold"],[["Plain","prioritize"]]]],["Plain"," hydrating that component."]],"body":[],"content":"Hydration is the final part of making you page interactive when using SSR. It happens after the [[JavaScript]] has been fetched and loaded. Previously, this part would block the pattern above, but with **selective hydration** each part can start hydrating whenever that part is ready. If the user starts interacting with a component before it's been fully hydrated, React will **prioritize** hydrating that component."}],"title":[["Plain","Suspense and SSR"]],"body":[],"content":"## Suspense and SSR"},{"id":"61915a86-fbb3-471a-8dc0-42b0109ba686","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-1e3d-4d9a-bafc-be34691b3075","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","evening kid"],"label":[["Plain",""]],"full_text":"[[evening kid]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-06-10"],"label":[["Plain",""]],"full_text":"[[2021-06-10]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","What’s new in React 18"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"www.youtube.com/watch?v=bpVRWrrfM1M"}],"label":[["Plain","https://www.youtube.com/watch?v=bpVRWrrfM1M"]],"full_text":"https://www.youtube.com/watch?v=bpVRWrrfM1M","metadata":""}]],"body":[],"content":"[[evening kid]]. ([[2021-06-10]]). _What’s new in React 18_. https://www.youtube.com/watch?v=bpVRWrrfM1M"},{"id":"61915a86-711f-403e-a309-252b0e86a7ee","format":"markdown","children":[],"title":[],"body":[["Paragraph",[["Plain",""],["Tag",[["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}]]],["Break_Line"]]]],"content":" #[[React]]"},{"id":"61915a86-94e8-4295-86cf-ce4529ecbe9b","format":"markdown","children":[],"title":[["Emphasis",[["Bold"],[["Plain","ID:"]]]],["Plain"," 210621072907"]],"body":[],"content":"**ID:** 210621072907"}]},{"id":"61915a86-6319-444f-817f-cdcd3b564674","page-name":"Good documentation is written by and for humans","properties":{"tags":["Development","Documentation"],"pid":210718220754},"children":[{"id":"61915ad6-3d6d-4e7c-a312-b60ffc9f4e86","properties":{"tags":["Development","Documentation"],"pid":210718220754},"format":"markdown","children":[],"content":"tags:: Development, Documentation,\npid:: 210718220754"},{"id":"61915a86-f0c3-42b1-a588-f1db5a790fcc","properties":{},"format":"markdown","children":[],"title":[["Plain","Writing good documentation is hard. Remember that you are writing for humans. It might be the first time they are seeing code like the one you are describing."]],"body":[],"content":"Writing good documentation is hard. Remember that you are writing for humans. It might be the first time they are seeing code like the one you are describing."},{"id":"61915a86-994f-4cef-9572-33658bf6b21e","properties":{},"format":"markdown","children":[],"title":[["Plain","Everyone has at least one example of good documentation. Write your documentation as that example, the way you would want to find it. "],["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}],["Plain"," as everyone might not have the same level of knowledge as you do."]],"body":[],"content":"Everyone has at least one example of good documentation. Write your documentation as that example, the way you would want to find it. [[Explain in plain words]] as everyone might not have the same level of knowledge as you do."},{"id":"61915a86-75ce-4061-8cbf-379cbb89db4a","format":"markdown","children":[],"title":[["Plain","There are tools that help with generating documentation, but it does not help you write good documentation. "],["Emphasis",[["Bold"],[["Plain","Generate documentation when possible, but put in extra effort to make it good."]]]]],"body":[],"content":"There are tools that help with generating documentation, but it does not help you write good documentation. **Generate documentation when possible, but put in extra effort to make it good.**"},{"id":"61915a86-8cda-4443-9d62-9c99191d130f","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-ed32-42bd-a30d-b5876992d02d","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Jason Etcovich"],"label":[["Plain",""]],"full_text":"[[Jason Etcovich]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2020-08-24"],"label":[["Plain",""]],"full_text":"[[2020-08-24]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"Assorted thoughts on documentation\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"jasonet.co/posts/thoughts-on-docs/"}],"label":[["Plain","Link"]],"full_text":"[Link](https://jasonet.co/posts/thoughts-on-docs/)","metadata":""}]],"body":[],"content":"[[Jason Etcovich]]. ([[2020-08-24]]). _\"Assorted thoughts on documentation\"_. [Link](https://jasonet.co/posts/thoughts-on-docs/)"}]},{"id":"61915a86-79aa-403a-a9aa-786477b6e3e5","page-name":"Thomas Boutell","properties":{"public":true},"children":[{"id":"61915a86-bd4d-4b20-a51c-69732d0d061b","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-7b07-4c08-8fd1-6b421c25d06e","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-27df-42e0-8882-4da8ce3cb3d7","page-name":"Kernel","properties":{"public":true},"children":[{"id":"61915a86-5fec-41a1-9f03-c9e2d041fb0f","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-30c9-4d35-b4ce-f358c1ee99df","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-9e61-4f2e-aa8b-c75de560bf47","page-name":"2021-07-18","children":[{"id":"61915a86-9f2b-4e88-a0ee-b3550396c7fa","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Good documentation is written by and for humans"],"label":[["Plain",""]],"full_text":"[[Good documentation is written by and for humans]]","metadata":""}]],"body":[],"content":"[[Good documentation is written by and for humans]]"}]},{"id":"61915a86-4d8f-4e14-9297-a52c5126c9ba","page-name":"2021-06-11","properties":{"public":true},"children":[{"id":"61915a86-70c3-4801-9041-787e12292d5f","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-906f-4f9b-b987-a1e930de70a9","format":"markdown","children":[{"id":"61915a86-905f-483a-b06c-497b27d07d3b","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Learn by doing side projects"],"label":[["Plain",""]],"full_text":"[[Learn by doing side projects]]","metadata":""}]],"body":[],"content":"[[Learn by doing side projects]]"},{"id":"61915a86-1705-4a21-9b8c-40436620d4f0","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Learning in public"],"label":[["Plain",""]],"full_text":"[[Learning in public]]","metadata":""}]],"body":[],"content":"[[Learning in public]]"},{"id":"61915a86-8775-495a-b498-b13555fe1b8f","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}]],"body":[],"content":"[[Explain in plain words]]"}],"title":[["Plain","A coworker asked for tips on how to get more advanced "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," knowledge. This got me thinking about how I do learning."]],"body":[],"content":"A coworker asked for tips on how to get more advanced [[React]] knowledge. This got me thinking about how I do learning."}]},{"id":"61915a86-f6b9-48c9-a31a-6cf3b4b274e7","page-name":"2021-06-30","children":[{"id":"61915a86-fc70-48d7-8949-414a6375ec8a","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Handling tech debt is like doing the dishes"],"label":[["Plain",""]],"full_text":"[[Handling tech debt is like doing the dishes]]","metadata":""}]],"body":[],"content":"[[Handling tech debt is like doing the dishes]]"}]},{"id":"61915a86-be29-4eaf-989b-07d3b49ab194","page-name":"2021-11-10","children":[{"id":"61915a86-f558-4b56-91a2-732ed32e53e6","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Use valueAsNumber and valueAsDate on inputs"],"label":[["Plain",""]],"full_text":"[[Use valueAsNumber and valueAsDate on inputs]]","metadata":""}]],"body":[],"content":"[[Use valueAsNumber and valueAsDate on inputs]]"},{"id":"61915a86-d7fd-4d83-a2e8-1f972ad83ab5","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Save disk space by deleting node_modules"],"label":[["Plain",""]],"full_text":"[[Save disk space by deleting node_modules]]","metadata":""}]],"body":[],"content":"[[Save disk space by deleting node_modules]]"}]},{"id":"61915a86-128c-42ba-8383-e578c1a80993","page-name":"Frontend","properties":{"public":true},"children":[{"id":"61915a86-16ae-4323-b3de-75cda7dfd259","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-772d-405f-8bff-46b51930c9e2","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-53e5-421f-9d06-c72d2e5daae4","page-name":"Handling tech debt is like doing the dishes","properties":{"tags":["Development"],"pid":210630160342},"children":[{"id":"61915afc-4ed5-41b8-893c-92354c9649c2","properties":{"tags":["Development"],"pid":210630160342},"format":"markdown","children":[],"content":"tags:: Development,\npid:: 210630160342"},{"id":"61915a86-057f-4b75-982c-9a3b621da9db","properties":{},"format":"markdown","children":[],"title":[["Plain","Whenever you procrastinate on doing the dishes – even if it's only a plate, a knife, and a fork – something happens. The dishes start to pile up since there's already something in the sink. If you have a dishwasher there might be a feeling that \"the dishwasher must be full or running or clean and I don't want to be the one to handle it\". You do this knowing full well that the problem will become more of a hassle with each item that gets added to the pile."]],"body":[],"content":"Whenever you procrastinate on doing the dishes – even if it's only a plate, a knife, and a fork – something happens. The dishes start to pile up since there's already something in the sink. If you have a dishwasher there might be a feeling that \"the dishwasher must be full or running or clean and I don't want to be the one to handle it\". You do this knowing full well that the problem will become more of a hassle with each item that gets added to the pile."},{"id":"61915a86-87c7-48b2-ab76-7b62ac9f01a4","format":"markdown","children":[],"title":[["Plain","The same can be said for "],["Link",{"url":["Page_ref","Technical debt"],"label":[["Plain",""]],"full_text":"[[Technical debt]]","metadata":""}],["Plain",". The longer we ignore or avoid the issues, the harder they'll be to clean up. "],["Emphasis",[["Bold"],[["Plain","When you spot something, take a short amount of time and fix it"]]]],["Plain",". It'll be much easier to do now when you are in the context. Or at least make a note, preferably with context, and make sure it's fixed straight after the feature has been released."]],"body":[],"content":"The same can be said for [[Technical debt]]. The longer we ignore or avoid the issues, the harder they'll be to clean up. **When you spot something, take a short amount of time and fix it**. It'll be much easier to do now when you are in the context. Or at least make a note, preferably with context, and make sure it's fixed straight after the feature has been released."}]},{"id":"61915a86-e15b-4c7d-9e46-dae502c038e0","page-name":"2018-06-26","properties":{"public":true},"children":[{"id":"61915a86-057e-45ff-8ad4-4cac0b02a76f","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-b963-410d-9732-7f06f873b51d","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-90b3-4b0b-9162-c96783c77985","page-name":"Explain in plain words","properties":{"tags":["Learning"],"pid":210611105334},"children":[{"id":"61915a86-19ce-4c17-8b15-fbe02ab07ea0","properties":{"tags":["Learning"],"pid":210611105334},"format":"markdown","children":[],"content":"tags:: Learning,\npid:: 210611105334"},{"id":"61915a86-7deb-473e-bba9-35bfc08efcfb","format":"markdown","children":[],"title":[["Plain","An efficient way of testing your knowledge is to try and explain the subject in simple words. If you're unable to do that you haven't understood the subject well enough. Identify where your knowledge is lacking and study those areas more until you can explain them in simple words."]],"body":[],"content":"An efficient way of testing your knowledge is to try and explain the subject in simple words. If you're unable to do that you haven't understood the subject well enough. Identify where your knowledge is lacking and study those areas more until you can explain them in simple words."},{"id":"61915a86-4602-4722-bdba-18f1e6fdcf8f","format":"markdown","children":[],"title":[["Plain","You should be able to get your point across in as few words as possible, but don't overthink your first draft. Publish it then go over it again and make changes."]],"body":[],"content":"You should be able to get your point across in as few words as possible, but don't overthink your first draft. Publish it then go over it again and make changes."},{"id":"61915a86-60aa-4138-bc94-67dad30947f5","format":"markdown","children":[],"title":[["Plain","A good way of testing this is by "],["Link",{"url":["Page_ref","Learning in public"],"label":[["Plain",""]],"full_text":"[[Learning in public]]","metadata":""}],["Plain",". Tell a friend about it, write a blog post, share on "],["Link",{"url":["Page_ref","Twitter"],"label":[["Plain",""]],"full_text":"[[Twitter]]","metadata":""}],["Plain","."]],"body":[],"content":"A good way of testing this is by [[Learning in public]]. Tell a friend about it, write a blog post, share on [[Twitter]]."},{"id":"61915a86-5efc-427c-a291-ce7bfdcda1ba","format":"markdown","children":[],"title":[["Plain","This is the basis of "],["Link",{"url":["Page_ref","Richard Feynman"],"label":[["Plain",""]],"full_text":"[[Richard Feynman]]","metadata":""}],["Plain","'s learning technique"]],"body":[],"content":"This is the basis of [[Richard Feynman]]'s learning technique"},{"id":"61915a86-7b36-4b33-a0c8-543b034944b2","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-815d-4f82-9f30-5205e5ae4ae3","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Shu Omi"],"label":[["Plain",""]],"full_text":"[[Shu Omi]]","metadata":""}],["Plain"," ("],["Link",{"url":["Page_ref","2020-10-23"],"label":[["Plain",""]],"full_text":"[[2020-10-23]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"Simple Feynman Technique for Studying\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"www.youtube.com/watch?v=GL6Z1DTJ-LQ"}],"label":[["Plain","Link"]],"full_text":"[Link](https://www.youtube.com/watch?v=GL6Z1DTJ-LQ)","metadata":""}]],"body":[],"content":"[[Shu Omi]] ([[2020-10-23]]). _\"Simple Feynman Technique for Studying\"_. [Link](https://www.youtube.com/watch?v=GL6Z1DTJ-LQ)"}]},{"id":"61915a86-605b-4d15-bb9d-ca3c3e1cb858","page-name":"Record utility","properties":{"public":true},"children":[{"id":"61915a86-05c8-4d8f-b236-ef37cd3c1f49","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-03b9-4b9b-b947-240f19403eab","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype"}],"label":[["Plain","Documentation"]],"full_text":"[Documentation](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype)","metadata":""}]],"body":[],"content":"[Documentation](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeystype)"},{"id":"61915a86-26c5-4f93-a642-34daa8878a2c","format":"markdown","children":[],"title":[["Plain","The "],["Emphasis",[["Bold"],[["Plain","Record"]]]],["Plain"," utility is available from "],["Link",{"url":["Page_ref","TypeScript"],"label":[["Plain",""]],"full_text":"[[TypeScript]]","metadata":""}],["Plain"," "],["Code","v2.1"],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#partial-readonly-record-and-pick"}],"label":[["Plain","Release notes"]],"full_text":"[Release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#partial-readonly-record-and-pick)","metadata":""}]],"body":[],"content":"The **Record** utility is available from [[TypeScript]] `v2.1`. [Release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#partial-readonly-record-and-pick)"}]},{"id":"61915a86-91e2-41ac-81ad-b0d621941792","page-name":"Contents","children":[{"id":"61915a86-a6df-4ed3-92e9-cee7d080edd1","format":"markdown","children":[],"title":[["Plain","Here I'm trying to collect ideas and thoughts, new findings, and reminders regarding software development. I see it as a "],["Emphasis",[["Italic"],[["Plain","second brain"]]]],["Plain"," for all things related to development. It's also also a way for me to practice "],["Link",{"url":["Page_ref","Learning in public"],"label":[["Plain",""]],"full_text":"[[Learning in public]]","metadata":""}]],"body":[],"content":"Here I'm trying to collect ideas and thoughts, new findings, and reminders regarding software development. I see it as a _second brain_ for all things related to development. It's also also a way for me to practice [[Learning in public]]"},{"id":"61915a86-c148-490c-a5d5-2e60e8bdb6ff","format":"markdown","children":[],"title":[["Plain","It's built using "],["Link",{"url":["Complex",{"protocol":"https","link":"logseq.com/"}],"label":[["Plain","Logseq"]],"full_text":"[Logseq](https://logseq.com/)","metadata":""}]],"body":[],"content":"It's built using [Logseq](https://logseq.com/)"},{"id":"61915a86-2fca-47f0-bc16-730ae6a5e786","format":"markdown","children":[],"title":[["Plain","I'm currently on paternal leave for the rest of 2021. Updates won't happen often."]],"body":[],"content":"I'm currently on paternal leave for the rest of 2021. Updates won't happen often."},{"id":"61915a86-0dd9-40c0-ac84-c7e02ee83002","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-26c8-44ec-8ee4-abfe6cc346ff","page-name":"PR","properties":{"public":true},"children":[{"id":"61915a86-297b-4162-8b3f-5e1ebf1d78cb","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-d151-4d54-866a-a2653d6a662a","format":"markdown","children":[],"title":[["Plain","A pull request"]],"body":[],"content":"A pull request"}]},{"id":"61915a86-8e70-4b88-8d5e-446647d11eab","page-name":"2021-10-01","children":[{"id":"61915a86-dc45-47d7-9ad7-ca7ec3e7586b","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Share shortcuts and plugins when teaching new developers"],"label":[["Plain",""]],"full_text":"[[Share shortcuts and plugins when teaching new developers]]","metadata":""}]],"body":[],"content":"[[Share shortcuts and plugins when teaching new developers]]"}]},{"id":"61915a86-066c-446f-b4c9-cdc4a9d9e6cb","page-name":"Errors","properties":{"public":true},"children":[{"id":"61915a86-9589-4a47-8f31-2f0804fc88e1","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-5982-4358-b3b4-6f33627e57ce","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61968e02-cc91-4a9e-b8ed-2e01b9402108","page-name":"Use the object's identifier type","properties":{"tags":["TypeScript","Development"],"pid":211117191049},"children":[{"id":"61968d8c-e7c5-44b0-89ce-3c7a9458c68e","properties":{"tags":["TypeScript","Development"],"pid":211117191049},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"tags:: TypeScript, Development,\npid:: 211117191049\n\n"},{"id":"61968d8c-4dcf-4b6c-8c9d-a575b6709c04","format":"markdown","children":[],"title":[["Plain","Select the object's identifier type instead of using for example "],["Code","string"],["Plain"," when you have a function that should only take a specific identifier. This will make the code easier to refactor and also make it more evident what the function is expecting."]],"body":[],"content":"Select the object's identifier type instead of using for example `string` when you have a function that should only take a specific identifier. This will make the code easier to refactor and also make it more evident what the function is expecting."},{"id":"61968d8c-e6c9-418e-8e20-76a2239b688a","properties":{},"format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["type Task = {","\n","id: string","\n","}","\n","\n","// This is fine, but might require refactoring if the id ever changes type","\n","function getTask(id: string) {}","\n","\n","// Better alternative","\n","function getTask(id: Task['id']) {}","\n"],"language":"ts","pos_meta":{"start_pos":8,"end_pos":202},"full_content":"```ts\ntype Task = {\nid: string\n}\n\n// This is fine, but might require refactoring if the id ever changes type\nfunction getTask(id: string) {}\n\n// Better alternative\nfunction getTask(id: Task['id']) {}\n```"}]],"content":"```ts\ntype Task = {\nid: string\n}\n\n// This is fine, but might require refactoring if the id ever changes type\nfunction getTask(id: string) {}\n\n// Better alternative\nfunction getTask(id: Task['id']) {}\n```"},{"id":"61968d8c-703d-45fa-b9d3-04e36b962042","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61968d8c-dec2-41a1-917f-4007171ac362","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Erik Rasmussen"],"label":[["Plain",""]],"full_text":"[[Erik Rasmussen]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-09"],"label":[["Plain",""]],"full_text":"[[2021-11-09]]","metadata":""}],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/erikras/status/1457999235564154882"}],"label":[["Plain","Tweet"]],"full_text":"[Tweet](https://twitter.com/erikras/status/1457999235564154882)","metadata":""}]],"body":[],"content":"[[Erik Rasmussen]]. [[2021-11-09]]. [Tweet](https://twitter.com/erikras/status/1457999235564154882)"}]},{"id":"61915a86-d921-4f1e-b378-c605af7156db","page-name":"2021-06-14","children":[{"id":"61915a86-69c8-48ff-b7e7-df7fc1822e32","format":"markdown","children":[],"title":[["Plain","The "],["Code","act"],["Plain"," utility in "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain"," makes your tests run closer to how React works in the browser. If you're using "],["Link",{"url":["Page_ref","Testing Library"],"label":[["Plain",""]],"full_text":"[[Testing Library]]","metadata":""}],["Plain"," you won't need it that often since the library already wraps the code in "],["Code","act"],["Plain"," when necessary."]],"body":[],"content":"The `act` utility in [[React]] makes your tests run closer to how React works in the browser. If you're using [[Testing Library]] you won't need it that often since the library already wraps the code in `act` when necessary."},{"id":"61915a86-e024-427c-a367-5b7d9afc8cdb","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Adding types to a React component in TypeScript"],"label":[["Plain",""]],"full_text":"[[Adding types to a React component in TypeScript]]","metadata":""}]],"body":[],"content":"[[Adding types to a React component in TypeScript]]"},{"id":"61915a86-eb15-4890-9959-99eb618f114e","format":"markdown","children":[],"title":[["Plain","The correct pronunciation for "],["Code",".png"],["Plain"," is "],["Emphasis",[["Bold"],[["Plain","ping"]]]],["Plain"," according to its inventor "],["Link",{"url":["Page_ref","Thomas Boutell"],"label":[["Plain",""]],"full_text":"[[Thomas Boutell]]","metadata":""}],["Plain",", although he states that pronouncing the acronym "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/boutell/status/1404410047980052492"}],"label":[["Plain","can never be considered wrong"]],"full_text":"[can never be considered wrong](https://twitter.com/boutell/status/1404410047980052492)","metadata":""}],["Plain",". "],["Tag",[["Plain","TIL"]]]],"body":[],"content":"The correct pronunciation for `.png` is **ping** according to its inventor [[Thomas Boutell]], although he states that pronouncing the acronym [can never be considered wrong](https://twitter.com/boutell/status/1404410047980052492). #TIL"}]},{"id":"61915a86-be32-4376-a6c7-a420f7d66555","page-name":"2021-03-04","properties":{"public":true},"children":[{"id":"61915a86-e04a-4e1e-a6da-6f0946dbed65","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-1da2-42f8-8c1d-27d6be075124","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-db25-4311-beef-7bb8f732990c","page-name":"2021-07-12","properties":{"public":true},"children":[{"id":"61915a86-3493-407a-bc98-b05a37ec24f4","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61968d8c-0262-41ab-af46-33f99f5c9c65","page-name":"Development","properties":{"public":true},"children":[{"id":"61915a86-85f3-4341-8a1b-3956e79c5b99","properties":{"public":true},"format":"markdown","children":[],"content":"public:: true\n"}]},{"id":"61915a86-6bc1-48ee-a5c2-ebf9e021aa28","page-name":"Harvard University","properties":{"public":true},"children":[{"id":"61915a86-13ff-4876-b73f-81960aa5ac7d","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-0ad8-4349-923e-be6ad76144a9","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-5fcd-4af4-b0aa-71a310c80dd8","page-name":"MDN","properties":{"public":true},"children":[{"id":"61915a86-288e-48fa-a930-23a6038da96a","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-3f0b-4083-b825-8c64e1fec661","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-0e27-4b65-b4b5-e1ff285353a2","page-name":"2021-09-22","children":[{"id":"61915a86-e7a4-468a-8035-fb6edb7f8414","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Difference between nullish coalescing (??) and logical or (||)"],"label":[["Plain",""]],"full_text":"[[Difference between nullish coalescing (??) and logical or (||)]]","metadata":""}]],"body":[],"content":"[[Difference between nullish coalescing (??) and logical or (||)]]"}]},{"id":"61915a86-e659-47c5-aee8-ee582c4178bf","page-name":"NERDTree","properties":{"public":true},"children":[{"id":"61915a86-c060-454b-97d3-e2bc73d339c3","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-fe70-4258-9ad5-ded23e7db630","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-75b9-4778-ae6c-fdc70476a6f7","page-name":"2021-06-13","children":[{"id":"61915a86-ed50-491f-ad03-2d98472c57d6","format":"markdown","children":[],"title":[],"body":[["Paragraph",[["Plain",""]]]],"content":""}]},{"id":"61915a86-1558-44cd-9c27-c5df56727112","page-name":"Adding types to a React component in TypeScript","properties":{"tags":["TypeScript","Development","React"],"pid":210614085847},"children":[{"id":"61915c00-b71d-4458-afb6-bf234810159e","properties":{"tags":["TypeScript","Development","React"],"pid":210614085847},"format":"markdown","children":[],"content":"tags:: TypeScript, Development, React\npid:: 210614085847"},{"id":"61915a86-13f7-4e87-9e2f-40fecb70260e","properties":{},"format":"markdown","children":[{"id":"61915a86-486e-4ce7-98d9-987ef9eb7b4a","format":"markdown","children":[],"title":[["Plain","The component will accept "],["Code","children"],["Plain"," even if we're not using it. This happens because "],["Code","React.FC"],["Plain"," implicitly sets the "],["Code","children"],["Plain"," and some other values."]],"body":[],"content":"The component will accept `children` even if we're not using it. This happens because `React.FC` implicitly sets the `children` and some other values."},{"id":"61915a86-309d-4e88-be49-c1d66004c35a","format":"markdown","children":[],"title":[["Plain","We can't use generics"]],"body":[],"content":"We can't use generics"},{"id":"61915a86-b5a1-4118-8975-31b5f4c903a8","format":"markdown","children":[],"title":[["Plain","We can't use function declarations"]],"body":[],"content":"We can't use function declarations"}],"title":[["Plain","In the types for "],["Link",{"url":["Page_ref","React"],"label":[["Plain",""]],"full_text":"[[React]]","metadata":""}],["Plain",", "],["Code","@types/react"],["Plain",", there's an included helper for typing components called "],["Code","React.FC"],["Plain"," (or the longer version "],["Code","React.FunctionComponent"],["Plain","). However, there are some downsides to using this."]],"body":[],"content":"In the types for [[React]], `@types/react`, there's an included helper for typing components called `React.FC` (or the longer version `React.FunctionComponent`). However, there are some downsides to using this."},{"id":"61915a86-03b0-481f-86fc-adf9d6a12906","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["import React from 'react'","\n"," ","\n","interface AppProps {","\n"," text: string","\n","}","\n"," ","\n","// Using React.FC","\n","const App: React.FC<AppProps> = ({ text }) => {","\n"," return <div>{text}</div>","\n","}","\n"," ","\n","// This would compile","\n","<App text=\"Testing\">I'm content that's not used</App>","\n"],"language":"tsx","pos_meta":{"start_pos":441,"end_pos":707},"full_content":"```tsx\nimport React from 'react'\n\ninterface AppProps {\n text: string\n}\n\n// Using React.FC\nconst App: React.FC<AppProps> = ({ text }) => {\n return <div>{text}</div>\n}\n\n// This would compile\n<App text=\"Testing\">I'm content that's not used</App>\n```"}]],"content":" ```tsx\nimport React from 'react'\n\ninterface AppProps {\n text: string\n}\n\n// Using React.FC\nconst App: React.FC<AppProps> = ({ text }) => {\n return <div>{text}</div>\n}\n\n// This would compile\n<App text=\"Testing\">I'm content that's not used</App>\n```"},{"id":"61915a86-b44e-4dbe-b373-8cedcb518106","format":"markdown","children":[],"title":[["Plain","Since React is nothing special you can use the regular syntax for defining variables to a function. This solves all of over pain points listed above."]],"body":[],"content":"Since React is nothing special you can use the regular syntax for defining variables to a function. This solves all of over pain points listed above."},{"id":"61915a86-e6f5-41ee-9008-76c7d2e619d6","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// Same import and interface","\n"," ","\n","// Using regular function typings","\n","const App = ({ text }: AppProps) => {","\n"," return <div>{text}</div>","\n","}","\n"," ","\n","// This would NOT compile","\n","<App text=\"Testing\">I'm content that's not used</App>","\n"," ","\n","// This would compile","\n","<App text=\"Testing\" />","\n"],"language":"tsx","pos_meta":{"start_pos":874,"end_pos":1158},"full_content":"```tsx\n// Same import and interface\n\n// Using regular function typings\nconst App = ({ text }: AppProps) => {\n return <div>{text}</div>\n}\n\n// This would NOT compile\n<App text=\"Testing\">I'm content that's not used</App>\n\n// This would compile\n<App text=\"Testing\" />\n```"}]],"content":" ```tsx\n// Same import and interface\n\n// Using regular function typings\nconst App = ({ text }: AppProps) => {\n return <div>{text}</div>\n}\n\n// This would NOT compile\n<App text=\"Testing\">I'm content that's not used</App>\n\n// This would compile\n<App text=\"Testing\" />\n```"},{"id":"61915a86-0f0b-4e46-a798-6be6ef3874f4","format":"markdown","children":[],"title":[["Plain","There are multiple types we could use for the component's return type: "],["Code","React.ReactElement"],["Plain",", "],["Code","JSX.Element"],["Plain",", "],["Code","React.ReactNode"],["Plain",". To not be too wide or too narrow with the typings, it's better to just rely on "],["Link",{"url":["Page_ref","TypeScript"],"label":[["Plain",""]],"full_text":"[[TypeScript]]","metadata":""}],["Plain","'s inference by not adding an explicit type."]],"body":[],"content":"There are multiple types we could use for the component's return type: `React.ReactElement`, `JSX.Element`, `React.ReactNode`. To not be too wide or too narrow with the typings, it's better to just rely on [[TypeScript]]'s inference by not adding an explicit type."},{"id":"61915a86-814c-4784-8682-f028e2d00031","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-d864-4500-a839-8c97058e794f","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Kent C. Dodds"],"label":[["Plain",""]],"full_text":"[[Kent C. Dodds]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-03-04"],"label":[["Plain",""]],"full_text":"[[2021-03-04]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","How to write a React Component in TypeScript"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"kentcdodds.com/blog/how-to-write-a-react-component-in-typescript"}],"label":[["Plain","Link"]],"full_text":"[Link](https://kentcdodds.com/blog/how-to-write-a-react-component-in-typescript)","metadata":""}]],"body":[],"content":"[[Kent C. Dodds]]. ([[2021-03-04]]). _How to write a React Component in TypeScript_. [Link](https://kentcdodds.com/blog/how-to-write-a-react-component-in-typescript)"}]},{"id":"61915a86-f7ec-4deb-a0c2-e39b61acf282","page-name":"Brittany Storoz","properties":{"public":true},"children":[{"id":"61915a86-45a2-42c5-8d5a-30c593bd6419","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-abbe-4dc8-a573-08a1a61256ba","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-e9b2-454d-90f7-24cfb0a1de63","page-name":"Use valueAsNumber and valueAsDate on inputs","properties":{"tags":["HTML"],"pid":211110140610},"children":[{"id":"61915a86-2711-4322-9947-30f69c9281a6","properties":{"tags":["HTML"],"pid":211110140610},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"tags:: HTML,\npid:: 211110140610\n\n"},{"id":"61915a86-1dac-49b2-9541-d54eae33624d","format":"markdown","children":[],"title":[["Plain","If you want to get the value of an input as a number or a date you can easily parse the value of a "],["Code","type=\"text\""],["Plain"," input. However, there's an easier solution by using "],["Code","valueAsNumber"],["Plain"," or "],["Code","valueAsDate"],["Plain",". The attributes are only available "],["Link",{"url":["Complex",{"protocol":"https","link":"www.w3.org/TR/2011/WD-html5-20110525/the-input-element.html#input-type-attr-summary"}],"label":[["Plain","for certain input types"]],"full_text":"[for certain input types](https://www.w3.org/TR/2011/WD-html5-20110525/the-input-element.html#input-type-attr-summary)","metadata":""}],["Plain",". The attributes return "],["Code","NaN"],["Plain"," if not available or if the value is invalid."]],"body":[],"content":"If you want to get the value of an input as a number or a date you can easily parse the value of a `type=\"text\"` input. However, there's an easier solution by using ``valueAsNumber`` or ``valueAsDate``. The attributes are only available [for certain input types](https://www.w3.org/TR/2011/WD-html5-20110525/the-input-element.html#input-type-attr-summary). The attributes return ``NaN`` if not available or if the value is invalid."},{"id":"61915a86-8c47-423e-a060-20f6567063d6","format":"markdown","children":[],"title":[["Plain","Browser support is great, "],["Code","valueAsNumber"],["Plain"," is supported by all browsers (even "],["Link",{"url":["Page_ref","IE"],"label":[["Plain",""]],"full_text":"[[IE]]","metadata":""}],["Plain",") and "],["Code","valueAsDate"],["Plain"," is supported by all browsers except IE."]],"body":[],"content":"Browser support is great, `valueAsNumber` is supported by all browsers (even [[IE]]) and ``valueAsDate`` is supported by all browsers except IE."},{"id":"61915a86-1577-4fbc-b8a4-88dd8036d0c4","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["// This will always return NaN since valueAsNumber is not available on text inputs","\n","<input type=\"text\" onChange={e => console.log(e.target.valueAsNumber)} />","\n"," ","\n","// Return the value as an integer or a float","\n","// depending on the input's step attribute","\n","<input type=\"number\" onChange={e => console.log(e.target.valueAsNumber)} />","\n"," ","\n","// Return the date as a UNIX timestamp, i.e. new Date().getTime()","\n","<input type=\"date\" onChange={e => console.log(e.target.valueAsNumber)} />","\n"," ","\n","// Return the date as a JS Date object","\n","<input type=\"date\" onChange={e => console.log(e.target.valueAsDate)} />","\n"],"language":"js","pos_meta":{"start_pos":622,"end_pos":1223},"full_content":"```js\n // This will always return NaN since valueAsNumber is not available on text inputs\n <input type=\"text\" onChange={e => console.log(e.target.valueAsNumber)} />\n \n // Return the value as an integer or a float\n // depending on the input's step attribute\n <input type=\"number\" onChange={e => console.log(e.target.valueAsNumber)} />\n \n // Return the date as a UNIX timestamp, i.e. new Date().getTime()\n <input type=\"date\" onChange={e => console.log(e.target.valueAsNumber)} />\n \n // Return the date as a JS Date object\n <input type=\"date\" onChange={e => console.log(e.target.valueAsDate)} />\n ```\n"}]],"content":"```js\n// This will always return NaN since valueAsNumber is not available on text inputs\n<input type=\"text\" onChange={e => console.log(e.target.valueAsNumber)} />\n\n// Return the value as an integer or a float\n// depending on the input's step attribute\n<input type=\"number\" onChange={e => console.log(e.target.valueAsNumber)} />\n\n// Return the date as a UNIX timestamp, i.e. new Date().getTime()\n<input type=\"date\" onChange={e => console.log(e.target.valueAsNumber)} />\n\n// Return the date as a JS Date object\n<input type=\"date\" onChange={e => console.log(e.target.valueAsDate)} />\n```"},{"id":"61915a86-a50c-48af-ad43-7308b40a06f7","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-62f9-4ecf-a371-4a799ce91e97","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","MDN"],"label":[["Plain",""]],"full_text":"[[MDN]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-10"],"label":[["Plain",""]],"full_text":"[[2021-11-10]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","HTMLInputElement"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement"}],"label":[["Plain","Link"]],"full_text":"[Link](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement)","metadata":""}]],"body":[],"content":"[[MDN]]. [[2021-11-10]]. _HTMLInputElement_. [Link](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement)"},{"id":"61915a86-e7ef-4ac3-86d6-76320bb0cf2e","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Can I Use"],"label":[["Plain",""]],"full_text":"[[Can I Use]]","metadata":""}],["Plain",". "],["Link",{"url":["Page_ref","2021-11-10"],"label":[["Plain",""]],"full_text":"[[2021-11-10]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","HTMLInputElement API: valueAsNumber"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"caniuse.com/mdn-api_htmlinputelement_valueasnumber"}],"label":[["Plain","Link"]],"full_text":"[Link](https://caniuse.com/mdn-api_htmlinputelement_valueasnumber)","metadata":""}]],"body":[],"content":"[[Can I Use]]. [[2021-11-10]]. _HTMLInputElement API: valueAsNumber_. [Link](https://caniuse.com/mdn-api_htmlinputelement_valueasnumber)"}]},{"id":"6193f7f5-cd9c-42a7-b628-9ee0b8debcc1","page-name":"2021-11-16","format":"markdown","children":[{"id":"6193f7f5-0d44-4f10-b449-97bff74c2595","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","People cost more than their tools"],"label":[["Plain",""]],"full_text":"[[People cost more than their tools]]","metadata":""}]],"body":[],"content":"[[People cost more than their tools]]"}]},{"id":"61915a86-14bc-41b3-9971-2809f199fda6","page-name":"React Podcast","properties":{"public":true},"children":[{"id":"61915a86-2d9f-445b-a8a1-d2277ffb36b2","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-32e1-43f8-adc1-cb3e90933842","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-f274-47d4-ae7e-b3afe1e1b137","page-name":"2020-12-17","properties":{"public":true},"children":[{"id":"61915a86-d305-4123-bf01-99681d729582","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-d454-4521-a1c5-5863f1d2e2ef","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-7ae5-40d8-898d-ad5c3c0d8637","page-name":"Don't use shorthands in CSS","properties":{"tags":["CSS","Development"],"pid":210427103751},"children":[{"id":"61915b56-e179-46df-ae66-a0cc93e035b3","properties":{"tags":["CSS","Development"],"pid":210427103751},"format":"markdown","children":[],"content":"tags:: CSS, Development\npid:: 210427103751"},{"id":"61915a86-6c23-4663-8a88-338b81cc4f54","properties":{},"format":"markdown","children":[],"title":[["Plain","In "],["Link",{"url":["Page_ref","CSS"],"label":[["Plain",""]],"full_text":"[[CSS]]","metadata":""}],["Plain"," we have shorthands which makes it easier to write certain properties, for example "],["Code","background"],["Plain"," or "],["Code","margin"],["Plain",". However, these affect more properties than what you're probably aiming for."]],"body":[],"content":"In [[CSS]] we have shorthands which makes it easier to write certain properties, for example `background` or `margin`. However, these affect more properties than what you're probably aiming for."},{"id":"61915a86-7455-4896-b4c8-8a89f75c3dd6","format":"markdown","children":[],"title":[["Plain","Instead use specific properties such as "],["Code","background-color"],["Plain"," or "],["Code","margin-left"]],"body":[],"content":"Instead use specific properties such as `background-color` or ``margin-left``"},{"id":"61915a86-814e-4a78-9049-7604bb89427e","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["/*","\n"," Here's an example where we want to change the background color to red.","\n","*/","\n",".test {","\n"," background: red;","\n","}","\n"," ","\n","/*","\n"," By using background we implicitly set all other values to initial","\n"," when we only wanted to change the background color","\n","*/","\n",".test {","\n"," background-image: initial;","\n"," background-position-x: initial;","\n"," background-position-y: initial;","\n"," background-size: initial;","\n"," background-repeat-x: initial;","\n"," background-repeat-y: initial;","\n"," background-attachment: initial;","\n"," background-origin: initial;","\n"," background-clip: initial;","\n"," background-color: red;","\n","}","\n"],"language":"css","pos_meta":{"start_pos":288,"end_pos":886},"full_content":"```css\n/*\n Here's an example where we want to change the background color to red.\n*/\n.test {\n background: red;\n}\n \n/*\n By using background we implicitly set all other values to initial\n when we only wanted to change the background color\n*/\n.test {\n background-image: initial;\n background-position-x: initial;\n background-position-y: initial;\n background-size: initial;\n background-repeat-x: initial;\n background-repeat-y: initial;\n background-attachment: initial;\n background-origin: initial;\n background-clip: initial;\n background-color: red;\n}\n```"}]],"content":" ```css\n/*\n Here's an example where we want to change the background color to red.\n*/\n.test {\n background: red;\n}\n \n/*\n By using background we implicitly set all other values to initial\n when we only wanted to change the background color\n*/\n.test {\n background-image: initial;\n background-position-x: initial;\n background-position-y: initial;\n background-size: initial;\n background-repeat-x: initial;\n background-repeat-y: initial;\n background-attachment: initial;\n background-origin: initial;\n background-clip: initial;\n background-color: red;\n}\n```"},{"id":"61915a86-0c98-4990-bb31-7279ca6de2cc","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-3f51-46e3-944a-7cd3bf0ce780","properties":{},"format":"markdown","children":[],"title":[["Plain","CSS Wizardry. ("],["Link",{"url":["Page_ref","2016-12-12"],"label":[["Plain",""]],"full_text":"[[2016-12-12]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"CSS Shorthand Syntax Considered an Anti-Pattern\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"csswizardry.com/2016/12/css-shorthand-syntax-considered-an-anti-pattern/"}],"label":[["Plain","Link"]],"full_text":"[Link](https://csswizardry.com/2016/12/css-shorthand-syntax-considered-an-anti-pattern/)","metadata":""}]],"body":[],"content":"CSS Wizardry. ([[2016-12-12]]). _\"CSS Shorthand Syntax Considered an Anti-Pattern\"_. [Link](https://csswizardry.com/2016/12/css-shorthand-syntax-considered-an-anti-pattern/)"}]},{"id":"61915a86-a715-44f6-8389-27fc498f8e38","page-name":"React","properties":{"public":true},"children":[{"id":"61915a86-0725-4ca6-9e8e-e8beb357d220","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-5b7c-4ebd-916f-7f34d8897924","format":"markdown","children":[],"title":[["Link",{"url":["Complex",{"protocol":"https","link":"reactjs.org/docs/getting-started.html"}],"label":[["Plain","Documentation"]],"full_text":"[Documentation](https://reactjs.org/docs/getting-started.html)","metadata":""}]],"body":[],"content":"[Documentation](https://reactjs.org/docs/getting-started.html)"}]},{"id":"61915a86-7623-4d33-a31d-ed7ffeafcd92","page-name":"2021-06-18","children":[{"id":"61915a86-9386-41e9-a320-1b61b28bd2f6","format":"markdown","children":[{"id":"61915a86-6c55-4bb9-bf4d-0786edf1c7b4","format":"markdown","children":[],"title":[["Plain","I'm using "],["Link",{"url":["Page_ref","NERDTree"],"label":[["Plain",""]],"full_text":"[[NERDTree]]","metadata":""}],["Plain"," as my file explorer and the setting to display the sidebar to the right is"]],"body":[],"content":"I'm using [[NERDTree]] as my file explorer and the setting to display the sidebar to the right is"},{"id":"61915a86-41e0-4414-8a12-d31d5fc9632d","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["let g:NERDTreeWinPos = \"right\"","\n"],"language":"vim","pos_meta":{"start_pos":689,"end_pos":726},"full_content":"```vim\nlet g:NERDTreeWinPos = \"right\"\n```"}]],"content":"\t ```vim\nlet g:NERDTreeWinPos = \"right\"\n```"}],"title":[["Plain","I haven't thought about using my sidebar/file explorer to the right in "],["Link",{"url":["Page_ref","Neovim"],"label":[["Plain",""]],"full_text":"[[Neovim]]","metadata":""}],["Plain"," (or in any other "],["Link",{"url":["Page_ref","IDE"],"label":[["Plain",""]],"full_text":"[[IDE]]","metadata":""}],["Plain"," I've ever used for that matter). After reading through the answers in this "],["Link",{"url":["Complex",{"protocol":"https","link":"twitter.com/code/status/1346573944703348743"}],"label":[["Plain","Twitter question"]],"full_text":"[Twitter question](https://twitter.com/code/status/1346573944703348743)","metadata":""}],["Plain"," I found it interesting that with the sidebar to the right, the code won't shift when toggling it. I think a lot of people keep the file explorer open while developing and don't experience this, but I always close it when I don't use it. I'm going to try using the sidebar to the right for a while and see if it sticks."]],"body":[],"content":"I haven't thought about using my sidebar/file explorer to the right in [[Neovim]] (or in any other [[IDE]] I've ever used for that matter). After reading through the answers in this [Twitter question](https://twitter.com/code/status/1346573944703348743) I found it interesting that with the sidebar to the right, the code won't shift when toggling it. I think a lot of people keep the file explorer open while developing and don't experience this, but I always close it when I don't use it. I'm going to try using the sidebar to the right for a while and see if it sticks."}]},{"id":"61915a86-90a6-41f7-8261-2f8f02dbc393","page-name":"Firefox","properties":{"public":true},"children":[{"id":"61915a86-486e-48e2-aca5-19b6781e5617","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-c0cf-4061-9766-638d2288c8d1","format":"markdown","children":[],"title":[],"body":[],"content":""}]},{"id":"61915a86-c731-4afd-a985-5eb7ac32580d","page-name":"AbortController can be used to cancel multiple request","properties":{"tags":["Development","React"],"pid":210622110339},"children":[{"id":"61915b79-75d9-4652-a172-e3d8f7533fac","properties":{"tags":["Development","React"],"pid":210622110339},"format":"markdown","children":[],"content":"tags:: Development, React\npid:: 210622110339"},{"id":"61915a86-e179-4804-94a0-4160eab278a1","properties":{},"format":"markdown","children":[],"title":[["Plain","Let's say the user clicks a link while we are still loading some data. Then we can use "],["Code","AbortController"],["Plain",", a controller object that allows us to abort "],["Emphasis",[["Bold"],[["Plain","one or more web requests"]]]],["Plain",", to tell the browser to cancel and ignore the request."]],"body":[],"content":"Let's say the user clicks a link while we are still loading some data. Then we can use ``AbortController``, a controller object that allows us to abort **one or more web requests**, to tell the browser to cancel and ignore the request."},{"id":"61915a86-9264-443f-ba84-5433052e5580","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["const { signal } = new AbortController();","\n"," ","\n","// Pass the same signal to multiple promises","\n","fetch('url-one', { signal });","\n","fetch('url-two', { signal });","\n"," ","\n","// Cancel all requests","\n","controller.abort();","\n"],"language":"js","pos_meta":{"start_pos":249,"end_pos":459},"full_content":"``` js\nconst { signal } = new AbortController();\n\n// Pass the same signal to multiple promises\nfetch('url-one', { signal });\nfetch('url-two', { signal });\n\n// Cancel all requests\ncontroller.abort();\n```"}]],"content":" ``` js\nconst { signal } = new AbortController();\n\n// Pass the same signal to multiple promises\nfetch('url-one', { signal });\nfetch('url-two', { signal });\n\n// Cancel all requests\ncontroller.abort();\n```"},{"id":"61915a86-27cf-4da9-be21-c1adf83de310","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-24d7-4571-a7e9-42134b556d83","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Ryan Florence"],"label":[["Plain",""]],"full_text":"[[Ryan Florence]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-06-21"],"label":[["Plain",""]],"full_text":"[[2021-06-21]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","\"AbortController\""]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"ryanflorence.dev/p/abortcontroller"}],"label":[["Plain","Link"]],"full_text":"[Link](https://ryanflorence.dev/p/abortcontroller)","metadata":""}]],"body":[],"content":"[[Ryan Florence]]. ([[2021-06-21]]). _\"AbortController\"_. [Link](https://ryanflorence.dev/p/abortcontroller)"},{"id":"61915a86-05ad-4fd4-ae88-97dbc9a99116","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","MDN"],"label":[["Plain",""]],"full_text":"[[MDN]]","metadata":""}],["Plain",". "],["Emphasis",[["Italic"],[["Plain","AbortController"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"developer.mozilla.org/en-US/docs/Web/API/AbortController"}],"label":[["Plain","Link"]],"full_text":"[Link](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)","metadata":""}]],"body":[],"content":"[[MDN]]. _AbortController_. [Link](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)"}]},{"id":"61915a86-7bb8-4f8c-b762-0f67b66e74c1","page-name":"2021-06-22","children":[{"id":"61915a86-4e0e-405c-b59e-caaecd539312","format":"markdown","children":[{"id":"61915a86-176c-4067-bc55-9193400a3bf7","format":"markdown","children":[{"id":"61915a86-26ab-4448-92ea-52a46f118133","format":"markdown","children":[],"title":[["Plain","Use cartoons or illustrations instead of writing text"]],"body":[],"content":"Use cartoons or illustrations instead of writing text"},{"id":"61915a86-270f-4cff-acaf-8879bdf5f8d7","format":"markdown","children":[],"title":[["Plain","Limit slang in issues/"],["Link",{"url":["Page_ref","PR"],"label":[["Plain",""]],"full_text":"[[PR]]","metadata":""}],["Plain","s. "],["Link",{"url":["Page_ref","Explain in plain words"],"label":[["Plain",""]],"full_text":"[[Explain in plain words]]","metadata":""}]],"body":[],"content":"Limit slang in issues/[[PR]]s. [[Explain in plain words]]"},{"id":"61915a86-01af-4e9d-b48b-830e8c2ea543","format":"markdown","children":[],"title":[["Plain","Work with native speakers of other languages to create better documentation"]],"body":[],"content":"Work with native speakers of other languages to create better documentation"}],"title":[["Plain","Tech is full of jargon which can be hard for everyone to understand. Some languages might not even have a name for a certain topic. Here are a few ways that can help make things easier to understand"]],"body":[],"content":"Tech is full of jargon which can be hard for everyone to understand. Some languages might not even have a name for a certain topic. Here are a few ways that can help make things easier to understand"}],"title":[["Link",{"url":["Page_ref","The Etymology of Programming"],"label":[["Plain",""]],"full_text":"[[The Etymology of Programming]]","metadata":""}]],"body":[],"content":"[[The Etymology of Programming]]"},{"id":"61915a86-1429-40b7-b088-ffc04421b625","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Always use real variable names in examples"],"label":[["Plain",""]],"full_text":"[[Always use real variable names in examples]]","metadata":""}]],"body":[],"content":"[[Always use real variable names in examples]]"},{"id":"61915a86-a827-45c9-96c9-85b1213084dd","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Don't use shorthands in CSS"],"label":[["Plain",""]],"full_text":"[[Don't use shorthands in CSS]]","metadata":""}]],"body":[],"content":"[[Don't use shorthands in CSS]]"},{"id":"61915a86-e535-4256-9575-8a250b01e762","format":"markdown","children":[],"title":[["Plain","I keep forgetting the official names for each part of the structure of CSS. Hopefully writing it down will help future me in remembering it - "],["Link",{"url":["Page_ref","Structure of CSS"],"label":[["Plain",""]],"full_text":"[[Structure of CSS]]","metadata":""}],["Plain","."]],"body":[],"content":"I keep forgetting the official names for each part of the structure of CSS. Hopefully writing it down will help future me in remembering it - [[Structure of CSS]]."},{"id":"61915a86-e326-4b4f-ac2f-5cfedd718dfc","format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","AbortController can be used to cancel multiple request"],"label":[["Plain",""]],"full_text":"[[AbortController can be used to cancel multiple request]]","metadata":""}]],"body":[],"content":"[[AbortController can be used to cancel multiple request]]"}]},{"id":"61915a86-04d9-4529-a910-64c136760c75","page-name":"Rewriting Git commit history","properties":{"tags":["Git"],"pid":210609102742},"children":[{"id":"61968dc8-ad6d-4c2a-8a88-290bd4189b55","properties":{"tags":["Git"],"pid":210609102742},"format":"markdown","children":[],"content":"tags:: Git,\npid:: 210609102742"},{"id":"61915a86-a180-4d94-a593-876cb6f34fb8","properties":{},"format":"markdown","children":[{"id":"61915a86-2ff8-4752-80a5-f822028f3f76","format":"markdown","children":[],"title":[["Plain","Commit A (sha: 123)"]],"body":[],"content":"Commit A (sha: 123)"},{"id":"61915a86-e54c-4e2f-9c3e-937c16aa7a21","format":"markdown","children":[],"title":[["Plain","Commit B (sha: 456)"]],"body":[],"content":"Commit B (sha: 456)"},{"id":"61915a86-6f04-4d62-bd51-27eefdfe04ad","format":"markdown","children":[],"title":[["Plain","Commit C (sha: 789)"]],"body":[],"content":"Commit C (sha: 789)"}],"title":[["Plain","If you want to fix a commit inside a "],["Link",{"url":["Page_ref","PR"],"label":[["Plain",""]],"full_text":"[[PR]]","metadata":""}],["Plain"," you can use "],["Link",{"url":["Page_ref","Git"],"label":[["Plain",""]],"full_text":"[[Git]]","metadata":""}],["Plain"," rebasing and the easiest way to do it is using an interactive rebase. Let's say you have three commits:"]],"body":[],"content":"If you want to fix a commit inside a [[PR]] you can use [[Git]] rebasing and the easiest way to do it is using an interactive rebase. Let's say you have three commits:"},{"id":"61915a86-ac29-48e0-a3cb-87aceae98726","format":"markdown","children":[],"title":[["Plain","Now you want to change "],["Emphasis",[["Italic"],[["Plain","Commit B"]]]],["Plain",". Start by finding its "],["Link",{"url":["Page_ref","SHA"],"label":[["Plain",""]],"full_text":"[[SHA]]","metadata":""}],["Plain"," ID using "],["Code","git log"],["Plain",", in this example we've called it "],["Code","456"],["Plain","."]],"body":[],"content":"Now you want to change _Commit B_. Start by finding its [[SHA]] ID using `git log`, in this example we've called it `456`."},{"id":"61915a86-a57c-4e9e-b246-2a7ce189e53f","format":"markdown","children":[],"title":[["Plain","Run "],["Code","git rebase -i 456^"],["Plain"," to start an interactive rebase. Note the "],["Code","^"],["Plain"," at the end which "],["Emphasis",[["Bold"],[["Plain","includes the commit in question in the rebase"]]]]],"body":[],"content":"Run `git rebase -i 456^` to start an interactive rebase. Note the `^` at the end which **includes the commit in question in the rebase**"},{"id":"61915a86-8070-4cd9-be04-1a708d3d0a66","format":"markdown","children":[{"id":"61915a86-c30d-4070-8b4e-7b8253fc82a7","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["pick 456 Commit B","\n","pick 789 Commit C","\n","\t ","\n","# Commands","\n","# p, pick <commit> = use commit","\n","# e, edit <commit> = use commit, but stop for amending","\n","# ...","\n"],"language":"md","pos_meta":{"start_pos":606,"end_pos":771},"full_content":"```md\npick 456 Commit B\npick 789 Commit C\n\n# Commands\n# p, pick <commit> = use commit\n# e, edit <commit> = use commit, but stop for amending\n# ...\n```"}]],"content":"\t ```md\npick 456 Commit B\npick 789 Commit C\n\n# Commands\n# p, pick <commit> = use commit\n# e, edit <commit> = use commit, but stop for amending\n# ...\n```"},{"id":"61915a86-7b8b-4b33-afcb-2deb004b2f38","format":"markdown","children":[],"title":[["Plain","Notice the "],["Emphasis",[["Italic"],[["Plain","edit"]]]],["Plain"," command, which is exactly what we want. Alter the line for "],["Emphasis",[["Italic"],[["Plain","Commit B"]]]],["Plain"," with the edit command instead of the pick command."]],"body":[],"content":"Notice the _edit_ command, which is exactly what we want. Alter the line for _Commit B_ with the edit command instead of the pick command."},{"id":"61915a86-ff11-4522-9712-0761a865fa28","format":"markdown","children":[],"title":[],"body":[["Src",{"lines":["edit 456 Commit B","\n","pick 789 Commit C","\n"],"language":"md","pos_meta":{"start_pos":929,"end_pos":974},"full_content":"```md\nedit 456 Commit B\npick 789 Commit C\n```"}]],"content":"\t ```md\nedit 456 Commit B\npick 789 Commit C\n```"},{"id":"61915a86-27c7-4d09-bd78-1adde8903036","format":"markdown","children":[],"title":[["Plain","After saving, "],["Link",{"url":["Page_ref","How to save and quit Vim"],"label":[["Plain",""]],"full_text":"[[How to save and quit Vim]]","metadata":""}],["Plain",", you'll be taken back in time to "],["Emphasis",[["Italic"],[["Plain","Commit B"]]]],["Plain"," where you can make the changes you set out to do."]],"body":[],"content":"After saving, [[How to save and quit Vim]], you'll be taken back in time to _Commit B_ where you can make the changes you set out to do."},{"id":"61915a86-079a-4189-9c68-60f094499727","format":"markdown","children":[],"title":[["Plain","Once your done with the changes, run "],["Code","git rebase --continue"],["Plain"," to take you back to the present."]],"body":[],"content":"Once your done with the changes, run `git rebase --continue` to take you back to the present."}],"title":[["Plain","You'll be presented with a "],["Link",{"url":["Page_ref","Vim"],"label":[["Plain",""]],"full_text":"[[Vim]]","metadata":""}],["Plain"," buffer that would look something like:"]],"body":[],"content":"You'll be presented with a [[Vim]] buffer that would look something like:"},{"id":"61915a86-3ab3-43a5-b8cc-b9caf304c783","format":"markdown","children":[],"title":[["Plain","If you would run "],["Code","git log"],["Plain"," at this point you would notice that the commit SHAs for Commit B and Commit C have changed. This happened be we altered history using with our rebase. To update our PR we need to do a force push, "],["Code","git push -f"]],"body":[],"content":"If you would run `git log` at this point you would notice that the commit SHAs for Commit B and Commit C have changed. This happened be we altered history using with our rebase. To update our PR we need to do a force push, `git push -f`"},{"id":"61915a86-3dc1-47d2-8754-27120698aaaf","format":"markdown","children":[],"title":[],"body":[["Custom","warning",null,[["Paragraph",[["Plain","Only do this in pull requests, don't alter your commits on you default branch."],["Break_Line"]]]],"Only do this in pull requests, don't alter your commits on you default branch.\n"]],"content":" #+BEGIN_WARNING\nOnly do this in pull requests, don't alter your commits on you default branch.\n#+END_WARNING"},{"id":"61915a86-2088-48a5-b7e6-f086f1d7237a","format":"markdown","children":[],"title":[],"body":[["Horizontal_Rule"]],"content":" ---"},{"id":"61915a86-1e7f-4767-a4b1-10651f6ad97d","properties":{},"format":"markdown","children":[],"title":[["Link",{"url":["Page_ref","Johnny Ji"],"label":[["Plain",""]],"full_text":"[[Johnny Ji]]","metadata":""}],["Plain",". ("],["Link",{"url":["Page_ref","2021-06-08"],"label":[["Plain",""]],"full_text":"[[2021-06-08]]","metadata":""}],["Plain","). "],["Emphasis",[["Italic"],[["Plain","Engineering Culture: Keeping a Clean Commit History"]]]],["Plain",". "],["Link",{"url":["Complex",{"protocol":"https","link":"johnnyisji.medium.com/engineering-culture-keeping-a-clean-commit-history-453f950c1f2d"}],"label":[["Plain","Link"]],"full_text":"[Link](https://johnnyisji.medium.com/engineering-culture-keeping-a-clean-commit-history-453f950c1f2d)","metadata":""}]],"body":[],"content":"[[Johnny Ji]]. ([[2021-06-08]]). _Engineering Culture: Keeping a Clean Commit History_. [Link](https://johnnyisji.medium.com/engineering-culture-keeping-a-clean-commit-history-453f950c1f2d)"}]},{"id":"61915a86-bc7d-47d7-afbe-ffbe216c54ba","page-name":"Nielsen Norman Group","properties":{"public":true},"children":[{"id":"61915a86-07dc-4a50-916a-e702e25f2f17","properties":{"public":true},"format":"markdown","children":[],"body":[["Paragraph",[["Break_Line"]]]],"content":"public:: true\n\n"},{"id":"61915a86-c827-4a74-82b9-73e10424126f","format":"markdown","children":[],"title":[],"body":[],"content":""}]}]}