<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amber</title>
    <description>The latest articles on DEV Community by Amber (@ambrwlsn).</description>
    <link>https://dev.to/ambrwlsn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F256198%2Fa2f90bdd-4c54-4078-afb8-614f35dea706.jpg</url>
      <title>DEV Community: Amber</title>
      <link>https://dev.to/ambrwlsn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ambrwlsn"/>
    <language>en</language>
    <item>
      <title>Nevertheless, Amber Kept Coding!</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Sat, 06 Mar 2021 11:39:55 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/nevertheless-amber-kept-coding-42l9</link>
      <guid>https://dev.to/ambrwlsn/nevertheless-amber-kept-coding-42l9</guid>
      <description>&lt;p&gt;When I'm asked to describe my journey into tech, I always start with &lt;a href="https://codebar.io/"&gt;codebar&lt;/a&gt;. This is the weekly workshop that helped give me the skills and confidence to seek out my first job as a web developer. &lt;/p&gt;

&lt;p&gt;I got my first job in mid-2017 and the company seemed excited to take me on, even though they didn't necessarily have an intern position open. Before starting, I had built a personal website and done some coding challenges. &lt;/p&gt;

&lt;p&gt;The internship was overall ok but there were moments that made me feel down such as being asked if I really enjoy JavaScript and if not, did I want to choose a different career? Or being jokingly asked by a colleague "what, they really pay you?!". Or being told indirectly by the lead developer that I should go away and take a bootcamp first.&lt;/p&gt;

&lt;p&gt;Maybe they were out of line, but maybe they also had a point. Who knows? I know for sure that I still had an enormous amount to learn. But were the confidence knocks really going to help me get there? In hindsight they didn't help at all.&lt;/p&gt;

&lt;p&gt;Luckily at the same time I had wonderful and supportive people around me. It's a shame I wasn't working with or for them instead.&lt;/p&gt;

&lt;p&gt;My second job in tech wasn't much better on the support front. I was hired as a trainee but didn't get one-to-one meetings or help with measuring my progress. After 10 months I was told that I didn't even have the skills to become a junior developer, because a junior should "be able to take a simple project from start to finish alone". Hmm. Even back then, that opinion sounded off to me.&lt;/p&gt;

&lt;p&gt;My third and current job is really great. I was hired by two people who value non-technical expertise and people skills just as highly as technical expertise. The job was challenging from the start but I've learned so much there. If I hadn't been given the opportunity, I wouldn't have all that valuable experience behind me.&lt;/p&gt;

&lt;p&gt;What will 2021 look like for me? Well, it'll soon be the fourth year anniversary of my first developer job. Am I proud of what I achieved and learned in that time? Yes! Do I still feel imposter syndrome around my technical abilities? Yes! But if there's one thing I've learned, it's to make sure I am comfortable with being uncomfortable.&lt;/p&gt;

&lt;p&gt;Besides, many people have told me they admire what I achieved so far with my tech writing, helping organise codebar in Berlin, being involved in the web community, and more.&lt;/p&gt;

&lt;p&gt;The top three bits of advice I'd give to anyone who is new(ish) in tech, especially those who aren't white cis guys, is firstly that while there are insensitive people, there will always be 100 amazing people in their place to support and cheer you on. Being part of the web community has kept my motivation and sanity up! Secondly, it's okay to feel imposter syndrome. Everyone does, even super-technical people who make amazing things. Being a developer means you need to be comfortable with never knowing everything, and always be learning.&lt;/p&gt;

&lt;p&gt;Lastly - everyone works at their own pace, has their own strengths, and interests. Comparing yourself to others is never a good strategy. Only compare yourself to yourself. There is no way that you from today compared to you from 6 months ago has not progressed or learned anything. Above all, try to enjoy what you're doing and don't rush things for the sake of being the "best". 🙂&lt;/p&gt;

</description>
      <category>wecoded</category>
    </item>
    <item>
      <title>Writing a Winning Web Developer Resume</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Sat, 16 Jan 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/writing-a-winning-web-developer-resume-1le2</link>
      <guid>https://dev.to/ambrwlsn/writing-a-winning-web-developer-resume-1le2</guid>
      <description>&lt;p&gt;It's hiring season!&lt;/p&gt;

&lt;p&gt;Do you want a new web developer job? You might call yourself a frontend (front-end/front end) engineer, a UI developer, a full-stack engineer, a software engineer, etc. There are many different and fun combinations of job titles!&lt;/p&gt;

&lt;p&gt;I will assume you develop things for the web, so you are a web developer.&lt;/p&gt;

&lt;p&gt;This post will give you, a web developer, tips on how to make a good impression at companies you'd like to work at.&lt;/p&gt;

&lt;p&gt;Who cares about a good resume? Well, unless you know people at the company you want to work at, it's likely &lt;strong&gt;the first impression you'll make is with your resume&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips on writing your web developer resume
&lt;/h2&gt;

&lt;p&gt;There are loads of tips out there on how to write a good resume. Below are some of my favourites that I gathered from both applying for jobs and from reviewing applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write things you &lt;em&gt;achieved&lt;/em&gt;, not only things you &lt;em&gt;did&lt;/em&gt;&lt;/strong&gt;. For example, instead of "added lots of JavaScript features", try "added JavaScript features that lowered load time by 400ms". Did you save your company money? Cool! Did you reduce loading times? Awesome! Explain how you did it and how it benefited your company or customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evidence for how you helped your company succeed or improved customer experience allows reviewers to imagine how you could provide value at their own company.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make sure your listed skills are relevant&lt;/strong&gt;. It is not good to list a skill or technology just because you read a blog post about it or because it is popular. Focus on skills and technologies you have used, enjoyed, and want to use in your next job. There's nothing much worse than listing way too many skills for a job—mostly because it shows you don't really care about your application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding relevant skills gives a clearer impression of what you actually enjoy and want to do in your job.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separate your skills section into what you use daily, weekly, and monthly&lt;/strong&gt;. If you only used Redux once a few months back, it's best not to give the impression that you use it all the time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Being clear about how often you use different skills or technologies helps a reviewer understand your strengths.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep your "education" section simple&lt;/strong&gt;. Reviewers won't pay too much attention to it, especially since many web developers are entirely or partially self-taught.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details about your hands-on coding experience are most often more important than details about your studies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The person reviewing your resume is short on time but has lot of other resumes to look at&lt;/strong&gt;. Keep your resume short and concise. Imagine a reviewer has only thirty seconds to read each application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can read through your own resume in 30 seconds then it is a good length.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Look at your resume and be honest - would you enjoy reading it?&lt;/strong&gt; If not, then try to add space between content, use whitespace well, choose a pleasant font, make sure spelling and grammar are correct, cut it down to maximum two pages etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tidy, short, and well-designed resume with no spelling or grammar errors shows you put effort into your application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add links to your projects and (if you want) social accounts&lt;/strong&gt;. Linking to project work on a personal website or repository is a great way to show off what you can do. But beware, reviewers will look at your source code! Linking to social accounts is good if you are comfortable with that and believe it can give a useful impression of you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Links to projects can help reviewers learn even more about you than what you can squeeze onto your resume.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Introduce yourself and your hobbies&lt;/strong&gt;. At the start of your resume it can be nice to introduce yourself by summarising your work experience and perhaps mentioning some of your hobbies. A reviewer may be glad to see that you have interests outside of coding.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Summarising your work experience along with your non-work experiences (hobbies) can help a reviewer see that there is more to you than coding.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consider not adding a photo&lt;/strong&gt;. It may seem tempting but it is not really necessary. Some companies even ask for no photo. It makes more sense for a reviewer to judge your competency by your experience and not how you look.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Humans can be biased and may unfairly judge your capabilities based on how you look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus tips for cover letters and interviews
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Being a web developer isn't only about writing code&lt;/strong&gt;. Aside from coding achievements, describe proud moments you had while interacting with others at work, or decisions you made on a problem that helped you avoid wasting time and building up technical debt. Describe how well you collaborate with others and show off your &lt;a href="https://www.aleksandra.codes/jira-to-javascript"&gt;problem solving skills&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Awareness of the importance of non-coding skills is crucial to being a good web developer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't address your cover letter with "Dear sir or madam"&lt;/strong&gt;. It's a good idea not to assume the gender of whoever is reviewing your application. Find another way to start your letter - for example "Dear {company name}" or "Hello!"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neutral language ensures that everyone is respected—including your reviewer and your customers.&lt;/p&gt;

</description>
      <category>job</category>
      <category>hiring</category>
      <category>cv</category>
      <category>resume</category>
    </item>
    <item>
      <title>2020 Year in Review</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Thu, 31 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/2020-year-in-review-4d1b</link>
      <guid>https://dev.to/ambrwlsn/2020-year-in-review-4d1b</guid>
      <description>&lt;p&gt;I got the idea to write a my first ever retrospective for the year from &lt;a href="https://monicalent.com/"&gt;Monica Lent&lt;/a&gt;. 🙏&lt;/p&gt;

&lt;p&gt;What a year it has been. Back in February I had no idea what the rest of the year was going to look like. I even attended a comedy night in Berlin where one of the comedians joked that she had coronavirus, and the audience actually found it genuinely funny!&lt;/p&gt;

&lt;p&gt;I didn't get to fly and visit any of my family or international friends this year, which has honestly sucked. I also don't see much of my local friends and family. I really miss everyone and it feels like a piece of me is missing. The pandemic has also delayed several of my important appointments.&lt;/p&gt;

&lt;p&gt;However, despite the pandemic and its effects on me this year, I am under no illusion of my privilege:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am happy. I am loved. I have a roof over my head. I am fed. I have disposable income. I enjoy my job. I am warm. I am healthy. I am educated. I have prospects. I have time. I can pursue hobbies. I am safe. I feel included.  &lt;/p&gt;

&lt;p&gt;Have you checked your privilege today?&lt;/p&gt;

&lt;p&gt;— Amber Wilson (@ambrwlsn90) &lt;a href="https://twitter.com/ambrwlsn90/status/1326196231371182083?ref_src=twsrc%5Etfw"&gt;November 10, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyway, in this post I want to try and focus on &lt;strong&gt;what I learned and achieved as a web engineer&lt;/strong&gt; this year.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I set out to do in 2020
&lt;/h2&gt;

&lt;p&gt;For 2020, I did not set out with a particular goal in mind. I was happy to go with the flow, work hard at my job, and maybe write a couple of blog posts on the side.&lt;/p&gt;

&lt;p&gt;One reason I may not have set goals for myself this year is because I had been working towards getting promoted to a mid-level web engineer since October 2019. I got promoted in March. I was pleased with this and did not make any more solid professional goals.&lt;/p&gt;

&lt;p&gt;For 2021, this is going to change. I've definitely got some plans for 2021. 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 5 Articles Released in 2020
&lt;/h2&gt;

&lt;p&gt;My posts on accessibilty and owning your own data did well this year!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/ambrwlsn/are-your-anchor-links-accessible-37ak"&gt;Are Your Anchor Links Accessible?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/ambrwlsn/from-gatsby-to-eleventy-2fk6"&gt;From Gatsby to Eleventy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amberwilson.co.uk/blog/grow-the-indieweb-with-webmentions/"&gt;Grow the IndieWeb with Webmentions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://localhost:8080/blog/how-and-when-to-use-react-usecallback/"&gt;How and when to use React useCallback()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/ambrwlsn/caches-are-for-copies-4i4d"&gt;Caches are for Copies&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've been using &lt;a href="https://plausible.io/"&gt;Plausible Analytics&lt;/a&gt; since mid-November and the above list is based on page views from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Achievements in 2020
&lt;/h2&gt;

&lt;p&gt;It felt really good to remember things I achieved this year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Got promoted to &lt;strong&gt;mid-level frontend engineer&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wrote &lt;strong&gt;16 blog posts&lt;/strong&gt; (averaging 1 post every ~23 days).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read &lt;strong&gt;12 books&lt;/strong&gt; (I wanted to read more than twice this - oops! I'll do better next year).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spoke on my first &lt;a href="https://aquestionofcode.com/62-what-is-it-like-to-have-a-mentor-amber-wilson/"&gt;web podcast&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up my own &lt;strong&gt;home office space&lt;/strong&gt; that I'm quite pleased with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Coached remotely at &lt;a href="https://codebar.io/berlin"&gt;codebar Berlin&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Re-designed and re-wrote my site with a static site generator called &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt;, which turned out to be the &lt;strong&gt;most fun I've had coding all year&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Began a &lt;a href="https://cs50.harvard.edu/college/2020/fall/"&gt;CS50 course&lt;/a&gt; with some nice people, so I can dive into some fundamental computer science topics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cooked a lot of new meals and made a recipe book so I can remember them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Got around 40 new plants, ¾three quarters of which I managed to keep alive.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks I want to give
&lt;/h2&gt;

&lt;p&gt;I want to thank a few people this year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;My partner for being amazing as always. You know why you're awesome!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://adactio.com/"&gt;Jeremy Keith&lt;/a&gt; for his support, mentorship, and being my most fave person ever to debate the web with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://hugogiraudel.com/"&gt;Kitty&lt;/a&gt; for their support, mentorship, and enviable ability to make pretty much anything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://includejs.dev/"&gt;Eva&lt;/a&gt; for being a bright light in the murkiness of this year, and getting people motivated to socialise and learn together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://twitter.com/khamiltonuk"&gt;Kristian&lt;/a&gt; for keeping codebar Berlin alive and kicking while staying as cool, calm, and collected as ever.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole of the web community this year has, as usual, been my rock. I can always count on my web friends to lift me up, support me, and motivate me to be the best I can be. I'm looking forward to being a part of this amazing community again next year. Huge love to everyone who is a part of it. ♥&lt;/p&gt;

&lt;h2&gt;
  
  
  Plans for 2021
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;a href="https://alistapart.com/article/the-career-management-document/"&gt;Career Management Document&lt;/a&gt;. In short, this involves writing down personal and professional achievements at least once a week. It helps you remember what you've done and learned, and helps you show this off to employers!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write 3 to 4 blog posts a month. By the end of the year, this means I would have written at least 36 blog posts. That's more than twice the amount I wrote this year! I want to write this many because there is so much I want to learn.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If I don't understand something, research it and write about it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be aware of the "curse of knowledge" and continue to write posts that developers of all levels can follow along with.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read 30 books!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do more &lt;a href="https://www.codewars.com/"&gt;codewars&lt;/a&gt; challenges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write at least one codewars challenge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Coach at least 5 times in a virtual &lt;a href="https://codebar.io/"&gt;codebar&lt;/a&gt; workshop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Record a video post and/or hold a live stream to teach something about web development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make an Eleventy plugin (e.g. for &lt;a href="https://indieweb.org/Webmention"&gt;Webmentions&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make more cute things, because the web is a place of expression where you can let your creativity roam free. ✨&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Happy New Year!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>review</category>
      <category>retro</category>
      <category>reflection</category>
    </item>
    <item>
      <title>How and when to use React useCallback()</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Tue, 22 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/how-and-when-to-use-react-usecallback-3378</link>
      <guid>https://dev.to/ambrwlsn/how-and-when-to-use-react-usecallback-3378</guid>
      <description>&lt;p&gt;In short, React's useCallback hook is used to wrap functions. It tells React to not re-create a wrapped function when a component re-renders, unless any of the useCallback's dependencies change. But when is it necessary to use useCallback?&lt;/p&gt;

&lt;p&gt;Many posts I have read on useCallback contain example code where a function wrapped in useCallback could just be moved outside of a component function body and into its own scope, or another simpler way. React is a smart library that is optimised to not need a hook like useCallback in most situations.&lt;/p&gt;

&lt;p&gt;The example code in this post aims to be more "real-world". Because of this, it's necessarily quite complex. As well as using common React hooks such as useState, useEffect, it also uses a number of JavaScript methods such as the fetch API, promises, filtering, splicing, destructuring, and currying.&lt;/p&gt;

&lt;p&gt;Even if you aren't an expert in all of the methods used in the example code, I hope you can still learn something!&lt;/p&gt;

&lt;h2&gt;
  
  
  Object references
&lt;/h2&gt;

&lt;p&gt;I want to explain an important fundamental JavaScript concept that will make understanding useCallback easier—object references:&lt;/p&gt;

&lt;p&gt;Functions are objects in JavaScript. Even if two functions are identical, they won't equal each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;14/10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)};&lt;/span&gt; &lt;span class="c1"&gt;// has a unique object reference&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;14/10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)};&lt;/span&gt; &lt;span class="c1"&gt;// has a unique object reference&lt;/span&gt;

&lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In comparison, if an object assigned to a variable is directly assigned to another variable, the references will match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;14/10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)};&lt;/span&gt; &lt;span class="c1"&gt;// has a unique object reference&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dog1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// assign the unique object reference of dog1 to a variable named dog2&lt;/span&gt;

&lt;span class="c1"&gt;// dog1 and dog2 point to same object reference&lt;/span&gt;
&lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;dog1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;dog2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the next section, we'll see why object references are fundamental to writing and understanding React apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example app
&lt;/h2&gt;

&lt;p&gt;This section will go through and explain each step of a &lt;strong&gt;dog park&lt;/strong&gt; example app 🐶. If you want to take a look at the final code, here is the &lt;a href="https://github.com/ambrwlsn/dog-park"&gt;Dog Park GitHub repository&lt;/a&gt;. If you want to see a live version of the app, here is the &lt;a href="https://the-dog-park.netlify.app/"&gt;Dog Park app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The initial features that I built into the dog park app were pretty cool. They let you set a name for your park and choose the number of dogs in it!&lt;/p&gt;

&lt;p&gt;Inside the function body of the DogPark component, there is a function called fetchDog. This function fetches an array of dogs from &lt;a href="https://documenter.getpostman.com/view/4016432/the-dog-api/RW81vZ4Z#77124c23-dc8b-48f0-9cc2-7e009ecf74fe"&gt;The Dog API by Postman&lt;/a&gt;. DogPark re-renders whenever a user interacts with any of its elements, including its child component, Dogs. &lt;strong&gt;Whenever DogPark re-renders, fetchDog will be re-created and receive a new object reference&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Dogs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Dogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;shuffle&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./shuffle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DogPark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Gets a new object reference when it is re-created.&lt;/span&gt;
  &lt;span class="c1"&gt;// It is re-created whenever DogPark re-renders.&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.thedogapi.com/v1/breeds/`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Dog Park&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name your dog park:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; 
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Add the perfect Dogs to your park! Maximum of 10.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dogs&lt;/span&gt; &lt;span class="na"&gt;onFetchDog&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchDog&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DogPark&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a look at the Dogs component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;onFetchDog&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNumber&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dogList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDogList&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Runs the "fetchDog" function when either the number&lt;/span&gt;
  &lt;span class="c1"&gt;// variable or the onFetchDog variable changes.&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;onFetchDog&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;onFetchDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
          &lt;span class="nx"&gt;setDogList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;fetchDog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onFetchDog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// dependencies of the useEffect&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Number of dogs:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; 
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dogList&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dogList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Dogs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useEffect in the Dogs component has in its dependency array the fetchDog function (which has been passed down as onFetchDog), and the numbers variable.&lt;/p&gt;

&lt;p&gt;An input with a type of number lives inside the Dogs component. Whenever the number of dogs is changed, Dogs will re-render and fetchDog will be run. This is good! It's what we want. Note: when state that lives inside a child component changes and the child is re-rendered, this will not trigger a re-render of the parent component.&lt;/p&gt;

&lt;p&gt;If state that lives inside the parent component changes and the parent is re-rendered, the child component will also re-render. You can usually work around this issue by wrapping the child component in &lt;a href="https://reactjs.org/docs/react-api.html#reactmemo"&gt;React.memo&lt;/a&gt;. But, if a value in the parent component that the child component depends on gets a new object reference, React.memo won't work. In our app, Dogs depends on the fetchDog function coming from DogPark.&lt;/p&gt;

&lt;p&gt;Whenever a character is typed into the "Name your dog park" input in DogPark, DogPark will re-render and fetchDog will be re-created and get a new object reference. Dogs will also re-render and because the fetchDog dependency in its useEffect has changed, the useEffect will trigger, and the fetchDog function will run. This means that the list of dogs inside Dogs will refresh every time a single character is typed into the "Name your dog park" input. That is not good! It's not what we want. But what can we do?&lt;/p&gt;

&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; wrap the fetchDog function inside DogPark into a useCallback to ensure it is not re-created each time DogPark re-renders. However, as the fetchDog function has no dependencies, it can safely be moved out of the function body of DogPark. This is a simpler way to ensure that fetchDog is not re-created every time DogPark re-renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This function now lives outside of the DogPark function&lt;/span&gt;
&lt;span class="c1"&gt;// body and so is not re-created whenever DogPark re-renders&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DogPark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// DogPark function body&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, so, useCallback wasn't needed. But now, a &lt;strong&gt;third feature&lt;/strong&gt; is going to be added to the app that &lt;em&gt;is&lt;/em&gt; going to require useCallback. This feature will be the ability to choose dogs that have names beginning with either A-M or N-Z.&lt;/p&gt;

&lt;p&gt;A new state variable and two radio buttons are added. And the fetch function is moved back into DogPark and altered a little:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DogPark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// New state variable&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCharRange&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A-M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.thedogapi.com/v1/breeds/`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
      &lt;span class="nx"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
        &lt;span class="c1"&gt;// Filters dogs depending on the value of&lt;/span&gt;
        &lt;span class="c1"&gt;// the new state variable "charRange"&lt;/span&gt;
        &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;charRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A-M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome to &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Dog Park&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Name your dog park:&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Add the perfect Dogs to your park! Maximum of 10.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Two new radio buttons */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        A-M 
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A-M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setDogHalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A-M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        N-Z
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N-Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setDogHalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N-Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dogs&lt;/span&gt; &lt;span class="na"&gt;onFetchDog&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchDog&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fetchDog function now relies on the charRange state that lives within DogPark. This means fetchDog has to live in the function body of DogPark. I thought I could solve this issue by passing charRange to the fetchDog function that's passed down to Dogs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Here, fetchDog is outside of DogPark and gets the&lt;/span&gt;
&lt;span class="c1"&gt;// charRange state as a curried value but the returned&lt;/span&gt;
&lt;span class="c1"&gt;// function is still re-created each time DogPark re-renders&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DogPark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Dogs&lt;/span&gt; &lt;span class="nx"&gt;onFetchDog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fetchDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though I successfully moved fetchDog out of DogPark, fetchDog is still re-created every time DogPark re-renders.&lt;/p&gt;

&lt;p&gt;So, fetchDog needs to stay within DogPark, and useCallback can help to avoid fetchDog being re-created every time DogPark re-renders. This means that when a character is typed into the "Name your dog park" input, even though DogPark re-renders, fetchDog keeps its object reference, and so the useEffect in Dogs is not triggered. And the dog list in Dogs is not needlessly refreshed!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Now the fetchDog function is wrapped in the&lt;/span&gt;
&lt;span class="c1"&gt;// useCallback hook, with "charRange" in the hook's&lt;/span&gt;
&lt;span class="c1"&gt;// dependency array.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchDog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.thedogapi.com/v1/breeds/`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
    &lt;span class="nx"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;charRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A-M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;M&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;charRange&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to actually use useCallback
&lt;/h2&gt;

&lt;p&gt;In most use cases, your application won't be affected if a function is re-created and gets a new object reference upon each render. Even so, it can be tempting to proactively wrap a function in a useCallback to improve app performance. However, this premature optimisation can actually do harm rather than doing good. A blog post by Kent Dodds explains &lt;a href="https://kentcdodds.com/blog/usememo-and-usecallback"&gt;when and when not to use useCallback&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A good way to approach using useCallback is reactively rather than proactively. This means that, depending on your components, use it when you obviously need to, and not as a premature performance optimization. In short, don't wrap every function living inside a function body in a useCallback.&lt;/p&gt;

&lt;p&gt;It's highly recommended that you have React linting in your development environment, so that your linter can suggest appropriate times to use useCallback.&lt;/p&gt;

&lt;p&gt;If your linter is not suggesting useCallback, but you see that your UI is re-rendering in unexpected ways (as in the example in this post), or you have an infinite loop, check to see whether useCallback helps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official React docs for &lt;a href="https://reactjs.org/docs/hooks-reference.html#useeffect"&gt;useEffect&lt;/a&gt; and &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecallback"&gt;useCallback&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kent Dodd's post on &lt;a href="https://kentcdodds.com/blog/usememo-and-usecallback"&gt;when to use (and not use) useCallback&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Abramov's &lt;a href="https://overreacted.io/a-complete-guide-to-useeffect/"&gt;guide on useEffect()&lt;/a&gt; offering a deep dive into React hooks&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>Are your Anchor Links Accessible?</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Mon, 14 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/are-your-anchor-links-accessible-37ak</link>
      <guid>https://dev.to/ambrwlsn/are-your-anchor-links-accessible-37ak</guid>
      <description>&lt;p&gt;One day I decided I wanted to add anchor links to each of the sections in my blog posts. Over the past few months, I'd seen these links on a lot of pages—from official documentation pages to smaller blog posts. I find them really useful for sharing sections of pages with other people!&lt;/p&gt;

&lt;p&gt;To make the different sections of my blog posts shareable, I decided to add an anchor link to all of the section headers (&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;s) in each of my posts.&lt;/p&gt;

&lt;p&gt;While researching the best way to do this, something I noticed again and again was that other sites had almost always implemented anchor links in an inaccessible way.&lt;/p&gt;

&lt;p&gt;Within a few hours, I had made a plugin to automate the addition of anchor links to my blog post sections, AND I had ensured the links were accessible!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are anchor links exactly?
&lt;/h2&gt;

&lt;p&gt;Anchor links provide a way to link to separate sections of a page. On this page, hover over the level two headings on desktop to see the links (the links are always visible on smaller screens).&lt;/p&gt;

&lt;p&gt;In essence, an anchor link is a link containing a URL fragment. This fragment usually appears at the end of a URL. It begins with a hash character (&lt;code&gt;#&lt;/code&gt;), and is followed by a string. This string identifies a section in a web page.&lt;/p&gt;

&lt;p&gt;For example, a page may have a section containing a section header element such as an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;. This element can be given an &lt;code&gt;id&lt;/code&gt; attribute. An anchor link is created when the value of the &lt;code&gt;id&lt;/code&gt; matches the &lt;code&gt;href&lt;/code&gt; value of an anchor (&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;) element on the same page. Consider the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine the web page containing this code had the following URL: &lt;code&gt;https://example.com/blog/nice-post/&lt;/code&gt;. Clicking on the hash character within the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element would do two things; the browser window would scroll to the beginning of the introduction section, and the URL would become &lt;code&gt;https://example.com/blog/nice-post/#introduction&lt;/code&gt;. This URL can be shared and when opened in a browser, the page will automatically scroll to the introduction section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility check
&lt;/h2&gt;

&lt;p&gt;Of course, I wanted to make sure the anchor links I had written were accessible. I turned on VoiceOver (a screen reader for MacOS), and using caps lock with arrow keys to interact with the page's content, I moved to my section heading. I found a few issues. Below is the &lt;strong&gt;first&lt;/strong&gt; version of my anchor link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;Introduction
&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element is inside the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, VoiceOver reads out "heading level 2 2 items, visited, link number introduction". A screen reader user who wanted to skip across multiple headings at once would have a nicer experience if they only heard the actual heading text (i.e. "introduction").&lt;/p&gt;

&lt;p&gt;I realised the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element should exist as a sibling of the heading element, rather than a child of it. This is so that the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; text content remains clear. Below is the &lt;strong&gt;second&lt;/strong&gt; version of my anchor link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element is outside the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, VoiceOver reads out "link number" for the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; and "heading level two introduction" for the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;. This is a problem, as the elements are not associated with each other in any way.&lt;/p&gt;

&lt;p&gt;Associating anchor links with what they link to is important. Some anchor links I found on a popular site have SVGs with no labels or titles as content. When there is no information about a link available, the screen reader falls back to the href value (e.g. &lt;code&gt;https://example.com/blog/nice-post/&lt;/code&gt;). This makes the purpose of the link hard to decipher.&lt;/p&gt;

&lt;p&gt;I realised I needed to better associate my section headings with their anchor links. Below is the &lt;strong&gt;third&lt;/strong&gt; version of my anchor link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"link to this heading"&lt;/span&gt; &lt;span class="na"&gt;aria-describedby=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attributes I added are &lt;code&gt;aria-label&lt;/code&gt; and &lt;code&gt;aria-describedby&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;aria label&lt;/code&gt; is read out by a screen reader in place of whatever child the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element has. This is necessary for anchor links, as these links often have a single character as text content. One alternative is to describe the link using text content, but visually hide it (hint: I removed this attribute in a later version of my anchor link - refer to the fifth version).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;aria describedby&lt;/code&gt; matches the &lt;code&gt;id&lt;/code&gt; of the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;. When the link is focused, "link, link to this heading" is read out, followed by "introduction". This is much better, but there could be one more small improvement—having the heading before the link (hint: I removed this attribute in a later version of my anchor link - refer to the fifth version).&lt;/p&gt;

&lt;p&gt;I realised that my anchor links would make more sense if the heading came before the link. Below is the &lt;strong&gt;fourth&lt;/strong&gt; version of my anchor link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"link to this heading"&lt;/span&gt; &lt;span class="na"&gt;aria-describedby=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VoiceOver reads the &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; out as "heading level 2 introduction" and the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; as, "link, link to this heading, introduction". When the heading is first, screen reader users may be able to associate a section heading more easily with its corresponding anchor link.&lt;/p&gt;

&lt;p&gt;While I made great progress by the fourth version of my anchor link, there are final some outstanding issues that I wanted to address. Thanks to my friend &lt;a href="https://hugogiraudel.com/"&gt;Kitty&lt;/a&gt; for helping me realise these outstanding issues. Be sure to keep up to date with Kitty's current &lt;a href="https://hugogiraudel.com/2020/12/01/a11y-advent-calendar/"&gt;A11y Advent Calendar&lt;/a&gt; and check out their other great posts. 🙂&lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;aria-label&lt;/code&gt; is not actually brilliant for accessibility, as some translation services can have trouble accessing its value. So, it's best to add text content to the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element, and make sure to visually hide it. This way, screen readers can still access it but it'll be visually hidden for other users. Second, the &lt;code&gt;#&lt;/code&gt; can be left in and hidden from screen readers using &lt;code&gt;aria-hidden&lt;/code&gt;, while still being visible on the page.&lt;/p&gt;

&lt;p&gt;Lastly, I removed &lt;code&gt;aria-describedby&lt;/code&gt; because the anchor link's text content now references the section heading.&lt;/p&gt;

&lt;p&gt;Here is the &lt;strong&gt;fifth&lt;/strong&gt; version of my anchor link:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;#&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Section titled introduction&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fifth and final version of my anchor link is the one I am using on this page, along with a wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for styling purposes. It is much better than the first version! However, if you can think of improvements, please let me know.&lt;/p&gt;

&lt;h2&gt;
  
  
  A word of caution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Edit (17th December):&lt;/strong&gt; Beware, there be dragons! 🐉 I realise that including a link (that has its own text content) as a child of a heading may seem tempting (as it can make styling an anchor link easier). However, it's worth repeating that this can harm accessibility.&lt;/p&gt;

&lt;p&gt;Version one of my example anchor link (see &lt;a href="https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/#accessibility-check"&gt;accessibility check&lt;/a&gt;) introduces the issues caused by placing a link inside a heading, but I want to provide some more context to why it is not a good idea! I'll do this by describing a handy feature of VoiceOver.&lt;/p&gt;

&lt;p&gt;VoiceOver (and likely also other screen readers) gives a nice overview of a page's section headings. This feature, called the web rotor, is accessed by default by pressing &lt;code&gt;caps lock&lt;/code&gt; + &lt;code&gt;u&lt;/code&gt; while VoiceOver is on. Below are two screenshots of the web rotor comparing how headings are formed, depending on whether a link is inside or not:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KPCyZUvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/img/headings-with-link.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KPCyZUvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/img/headings-with-link.png" alt="web rotor"&gt;&lt;/a&gt;VoiceOver web rotor displaying headings containing links&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rPxfPZD2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/img/headings-without-link.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rPxfPZD2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/img/headings-without-link.png" alt="web rotor"&gt;&lt;/a&gt;VoiceOver web rotor displaying headings without links&lt;/p&gt;

&lt;p&gt;If a link that has its own content is placed within a heading, the computed heading text may be more difficult for a screen reader user to understand. This can affect how clear a page's structure is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Another option
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Edit (18th December):&lt;/strong&gt; Despite warning against the following option above, I want to write about making a whole heading into an anchor link. Or, more specifically, wrapping the heading text content in a link. Several people across different sites have asked me why I didn't mention this option before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Interesting reading but why do you need the # symbol in the HTML at all?  &lt;/p&gt;

&lt;p&gt;Why not just make the whole heading the link (easier clicked too!) and use ::before or ::after to put the symbol there through CSS? &lt;a href="https://t.co/ecaDkZjJH0"&gt;https://t.co/ecaDkZjJH0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Barry Pollard (&lt;a class="comment-mentioned-user" href="https://dev.to/tunetheweb"&gt;@tunetheweb&lt;/a&gt;
) &lt;a href="https://twitter.com/tunetheweb/status/1338984100133294083?ref_src=twsrc%5Etfw"&gt;December 15, 2020&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think both options—using an icon as a link, and making the header a link (when the content of the link is the heading text)—can be valid. However, I have a few concerns with wrapping a heading's text content in a link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can be useful separate the anchor link from the heading so that the link can have its own text content&lt;/li&gt;
&lt;li&gt;It may be harder to select heading text wrapped in a link&lt;/li&gt;
&lt;li&gt;Both screen reader and non-screen reader users may find this option less familiar and not understand its purpose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are two examples of sites that implement anchor links where a link wraps the text content of a heading: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#Including_a_stylesheet"&gt;MDN Web Docs&lt;/a&gt; and &lt;a href="https://almanac.httparchive.org/en/2019/accessibility#introduction"&gt;The Web Almanac&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is a code example of an accessible anchor link where a link wraps the text content of a heading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#introduction"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Introduction&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Would you rather implement anchor links in this way? It is a simpler solution. However, it is also less flexible.&lt;/p&gt;

&lt;p&gt;Of course, the way a feature is implemented depends on your own personal use case. But, no matter which way you implement something, please remember to think of the user experience!&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating accessible anchor links
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/www.11ty.dev"&gt;Eleventy&lt;/a&gt; together with &lt;a href="https://github.com/markdown-it"&gt;markdown-it&lt;/a&gt; to convert my markdown files into HTML files.&lt;/p&gt;

&lt;p&gt;I tried finding a plugin that would help me to automate the addition of anchor links for all my &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; elements. I did find one but soon realised it didn't make accessible links possible. So, I decided to make my own plugin.&lt;/p&gt;

&lt;p&gt;There is handy &lt;a href="https://github.com/markdown-it/markdown-it/tree/master/docs"&gt;markdown-it developer documentation&lt;/a&gt; for people wanting to create plugins. Using these docs, a &lt;a href="https://markdown-it.github.io/"&gt;markdown-it demo page&lt;/a&gt;, and some inspiration from a plugin called &lt;a href="https://github.com/valeriangalliat/markdown-it-anchor"&gt;markdown-it-anchor&lt;/a&gt;, I wrote a plugin.&lt;/p&gt;

&lt;p&gt;Here is &lt;a href="https://github.com/ambrwlsn/website/blob/da2056c316fa45fa58b443b07be1ac4c5080912e/helpers/markdown-anchor-wat.js#L1"&gt;a permalink to my plugin file&lt;/a&gt;. It recreates parsing functions for opening and closing &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; elements from the &lt;code&gt;markdown-it&lt;/code&gt; library. In my &lt;code&gt;eleventy.config&lt;/code&gt; file, I &lt;code&gt;use&lt;/code&gt; (connect) the plugin with &lt;code&gt;markdown-it&lt;/code&gt;. This allows me to automatically add custom anchor links for all my level two headings.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>html</category>
    </item>
    <item>
      <title>Grow the IndieWeb with Webmentions</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Tue, 08 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/grow-the-indieweb-with-webmentions-33p6</link>
      <guid>https://dev.to/ambrwlsn/grow-the-indieweb-with-webmentions-33p6</guid>
      <description>&lt;p&gt;When I re-made my site with Eleventy, the pages didn't change much, but I had loads of fun adding new features. The most fun was &lt;strong&gt;webmentions&lt;/strong&gt; and I'm here to convince you to add them!&lt;/p&gt;

&lt;p&gt;First, let me step back and explain why webmentions exist—the IndieWeb.&lt;/p&gt;

&lt;h2&gt;IndieWeb&lt;/h2&gt;

&lt;p&gt;Check out this official description of the IndieWeb:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The IndieWeb is a community of individual personal websites, connected by simple standards, based on the principles of owning your domain, using it as your primary identity, to publish on your own site (optionally syndicate elsewhere), and own your data—&lt;strong&gt;indieweb.org&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, a community of personal websites, connected together, used as identities, that makes ownership of data possible. 🦄 🌈 How does this all work?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's a &lt;a href="https://indieweb.org/"&gt;great IndieWeb resource&lt;/a&gt;  that will tell you everything you need to know&lt;/li&gt;
&lt;li&gt;But, start here if you want to know &lt;a href="https://indieweb.org/why"&gt;why the IndieWeb deserves your attention&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;When you're convinced, see this handy page for a &lt;a href="https://indiewebify.me/"&gt; quick start to becoming a citizen of the IndieWeb&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;International IndieWebCamps are here to help—I wrote a &lt;a href="https://amberwilson.co.uk/blog/indiewebcamp/"&gt;post about my first IndieWebCamp visit&lt;/a&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QXG4C9Gc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/grow-the-indieweb-with-webmentions/img/indiewebcamp2017.png" alt="Nuernberg IndieWebCamp 2017"&gt;Nürnberg IndieWebCamp 2017 (I'm in the bottom right)
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Webmentions&lt;/h2&gt;

&lt;p&gt;Now the juicy stuff!&lt;/p&gt;

&lt;p&gt;I think the coolest thing about the IndieWeb is that it is decentralised. Currently, there is a handful of corporations that own much of our data. With webmentions, each person owns their own data and each person can communicate with others. Webmentions are basically a way to display on your personal site ways that others have interacted with your content.&lt;/p&gt;

&lt;p&gt;On my site I display mentions and bookmarks. It's possible for someone to link to one of my blog posts within one of their blog posts or bookmarks. If they do this, I won't know about it unless they let me know about it. &lt;a href="https://webmention.app/"&gt;Letting others know you've mentioned their posts can be done manually or can be automated&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I also display likes, retweets and replies on blog posts that I have tweeted about. If the URL to my post is in my tweet, I can gather the interactions on that tweet and display them on that post. Although most social media platforms do not support webmentions, it's possible to gather them by using a great free service called &lt;a href="https://brid.gy/"&gt;Bridgy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some people have had webmentions on their site for many years, so I am a bit behind. &lt;a href="https://adactio.com/journal/6495"&gt;Jeremy has had webmentions since 2013&lt;/a&gt;. But, there are more people posting content online than ever before, and personal websites aren't shown the love they used to get. &lt;/p&gt;

&lt;p&gt;So, there has never been a more pressing need to put content creation platforms (e.g. Medium) and social media platforms (e.g. Twitter) second, and put your very own little corner of the web first 💖&lt;/p&gt;

&lt;p&gt;I used Max Böck's post on &lt;a href="https://mxb.dev/blog/using-webmentions-on-static-sites/"&gt;using webmentions in Eleventy&lt;/a&gt; to get started. I was able to get something on the screen quickly with Max's advice, and then I refined the incoming data a bit. Here is a summary of what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign up via &lt;a href="https://webmention.io/"&gt;Webmention.io&lt;/a&gt; - if this doesn't work right away, check out ways to &lt;a href="https://indielogin.com/setup"&gt;set up your website for indie logins&lt;/a&gt; (I'm able to sign in by linking to my GitHub account on my site's homepage)&lt;/li&gt;
&lt;li&gt;Add two &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags to your HTML document's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element: &lt;code&gt;&amp;lt;link rel="pingback" href="https://webmention.io/{your-domain-here}/xmlrpc"&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;link rel="webmention" href="https://webmention.io/{your-domain-here}/webmention"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For social media mentions, sign up to &lt;a href="https://brid.gy/"&gt;Bridgy&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Fetch &lt;strong&gt;all&lt;/strong&gt; of your site's webmention data in JSON format using one of the &lt;a href="https://github.com/aaronpk/webmention.io#api"&gt;webmention endpoints described by IndieWebCamp co-founder Aaron Parecki&lt;/a&gt; and the API token provided by &lt;a href="https://webmention.io/"&gt;Webmention.io&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Shape your webmention data however you like - I filter webmentions into separate re-tweet, reply, like, mention, and bookmark functions using the &lt;code&gt;'wm-property'&lt;/code&gt; (check out the &lt;a href="https://github.com/ambrwlsn/website/blob/1d713ad9fbce19a9bd8821790fd51c1be62e1f76/src/filters/webmentions-filter.js#L51"&gt;filter functions&lt;/a&gt; and before you say anything, yes I know they could be DRYer)&lt;/li&gt;
&lt;li&gt;Use the data to display webmentions on your blog posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some of my webmentions (from &lt;a href="https://amberwilson.co.uk/blog/from-gatsby-to-eleventy/"&gt;my Gatsby to Eleventy post&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zof6Jzh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/grow-the-indieweb-with-webmentions/img/webmentions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zof6Jzh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/grow-the-indieweb-with-webmentions/img/webmentions.png" alt="Amber's webmentions on her Gatsby to Eleventy post"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If all of this seems too difficult and inaccessible, please don't give up! I thought getting webmentions on my little static site would be &lt;strong&gt;way too difficult&lt;/strong&gt;. But there are so many wonderful posts about setting up webmentions, and so many great people willing to help. I count myself as one of those people :) If you want to implement webmentions on your site and are stuck on any of the points I listed above, ping me on Twitter and I'll do my best to help out.&lt;/p&gt;

</description>
      <category>ssg</category>
      <category>eleventy</category>
      <category>webmentions</category>
      <category>indieweb</category>
    </item>
    <item>
      <title>From Gatsby to Eleventy</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Fri, 20 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/from-gatsby-to-eleventy-2fk6</link>
      <guid>https://dev.to/ambrwlsn/from-gatsby-to-eleventy-2fk6</guid>
      <description>&lt;p&gt;In this post I'll compare my experience building my personal blogging site (the one you're on now) with two static site generators (SSGs) - Gatsby and Eleventy.&lt;/p&gt;

&lt;p&gt;The first version of my site was rolled out with Bootstrap CSS and no framework, the second and third used SCSS and again no framework. The fourth version was built with a popular &lt;a href="https://www.gatsbyjs.com/"&gt;static site generator (SSG) called Gatsby&lt;/a&gt;. This SSG uses React and GraphQL. My learning curve from using no framework to using Gatsby was not huge though, as I use React and GraphQL at work.&lt;/p&gt;

&lt;p&gt;The fifth, and at the time of publishing this post, current, version of this site uses a &lt;a href="https://www.11ty.dev/"&gt;static site generator called Eleventy&lt;/a&gt;. I was a bit daunted about using this SSG, because the tools I was used to working with all day weren't baked in. This meant no default React, or GraphQL. This SSG would be a new paradigm for me to learn from scratch. I'd have to pick a templating language I had never used before, and learn how Eleventy manages data. Even so, there were a number of reasons I wanted to move from Gatsby to Eleventy.&lt;/p&gt;

&lt;p&gt;Firstly, I'll summarise the reasons that I decided to use Gatsby in the first place. It lets people write React, takes care of a lot of performance concerns for you, and has a lot of good starter templates. So, it's excellent for getting started quickly, getting a reasonably good site created, and offers a good developer experience. This was a big pull for me, in addition to all the hype it was creating a few years ago, and the fact I could already use its baked-in tools. Also, the fact I could have my very own, nice and shiny single page app (SPA) was a plus for me, at the time.&lt;/p&gt;

&lt;p&gt;Gatsby sounds really good, so why did I move to Eleventy? This is a question I've put a lot of thought in to. First, I want to explain that I didn't add any new features to the site between the Gatsby and Eleventy versions. The only thing that changed is that now, all the &lt;a href="https://amberwilson.co.uk/learn"&gt;learn posts&lt;/a&gt; have their own page, instead of existing on one page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits gained
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;As my Eleventy site outputs a non-SPA, I didn't need to check or ensure that it is server-rendered, is able to be crawled by search engines to allow good search engine optimisation (SEO), or works without JavaScript. Non-SPAs do all of this by default.&lt;/li&gt;
&lt;li&gt;A number of Gatsby plugins stopped some of the functionality on my site working. For example, Gatsby's progressive web app plugin caused my server-side rendering to stop working.&lt;/li&gt;
&lt;li&gt;My site is a personal blog site that does not have thousands of users or masses of data. So, I don't need to make sure I'm saving on bandwidth or server resources. If I &lt;strong&gt;did&lt;/strong&gt; need that, I would consider creating a SPA, as they tend to request fewer server resources across page views, compared to non-SPAs.&lt;/li&gt;
&lt;li&gt;I don't need to force users to download large chunks of React library in their browsers. Gatsby by default forces this, and requires a plugin to ensure that React is only used on the server.&lt;/li&gt;
&lt;li&gt;I didn't need to bother code-splitting any React components to ensure users aren't downloading my whole site on initial page load.&lt;/li&gt;
&lt;li&gt;I was able to gain more control over performance optimisations such as image rendering. When I first released my Gatsby site, I used their image plugin but ended up disliking several things about it, such as styling inflexibility, and inability to use the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;I know enough about web development that I can write performant code on my own. Therefore, I can do without plugins that enhance performance, but don't make it clear how they do so. Also, I prefer using my own skills to create things wherever possible, as it teaches me how things really work.&lt;/li&gt;
&lt;li&gt;I could pick and choose what JavaScript is necessary in the client (browser), thereby limiting the size of the JavaScript a user needs to download. The only JavaScript my site needs on the client-side is for the dark mode toggle, the blog search input, a tiny (and privacy-first) analytics tool, and some linked data (JSON-LD) for SEO.&lt;/li&gt;
&lt;li&gt;By writing lower-level template code (Nunjucks vs JSX), I felt like I had more control over the generated code, which allowed me to output better and more consistent HTML.&lt;/li&gt;
&lt;li&gt;Gatsby has GraphQL baked in. For a lot of use cases, especially a personal blog site, GraphQL is overpowered and can be a large learning curve for some.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges faced
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Eleventy is newer and maintained by less people than Gatsby. Therefore, I felt that Eleventy is a bit less feature-rich and has less documentation. Although honestly, this isn't a huge deal. Firstly, I found Eleventy simpler to use (less abstract), and found the documentation covers all the most important aspects of the SSG. Secondly, almost any time I needed extra help or information, I found it in the form of excellent blog posts or example repositories created by other web developers.&lt;/li&gt;
&lt;li&gt;One of the very few issues I couldn't find help with was the sharing of one type of data (blog post excerpts) across my Eleventy-powered site. Gatsby, along with React, makes it easy to see what data is being shared and how. Eleventy has a fantastic data-sharing API (in my case the data sharing was orchestrated between Nunjucks and the Eleventy config file). However, I found it to be quite abstracted and struggled a lot trying to get my blog post excerpt data to be easily shared across pages. In the end, I created a workaround for this, but this workaround is quite hacky. I plan to write about it in a separate post.&lt;/li&gt;
&lt;li&gt;I had to learn how to use the Nunjucks templating language. This is only a small nitpick, as the learning curve was in no way steep.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Concluding thoughts
&lt;/h2&gt;

&lt;p&gt;Using Gatsby has taught me a lot about single page apps, and that's important! Sometimes using it was frustrating, and a few things broke without me realising why or even when, but these experiences can be good lessons. Also, I am employed to work on a large SPA, and probably will continue to work on SPAs professionally for years to come, so any experience working with them is good!&lt;/p&gt;

&lt;p&gt;I believe it is a good idea to use the &lt;a href="https://adactio.com/journal/14327"&gt;least-powerful technology possible for any given task&lt;/a&gt;. Building with Eleventy made this possible for me. I find React and GraphQL nice to use, and I was daunted at the thought of not being able to use JSX. But, using simpler and lower-level tools such as Nunjucks made me feel more confident about my site's output (robust HTML and the least JavaScript possible), and I enjoyed the experience much more than I thought I would.&lt;/p&gt;

&lt;p&gt;Please don't take what I've written here as a reason not to choose Gatsby over Eleventy. I chose to re-write my site in Eleventy for several reasons. I have the knowledge to build in performance and accessibility myself, I realised I didn't need an SPA for my use case, and I wanted to use simpler, less powerful developer tools. I think developers should use the tools that suit them best. There is only one thing I want to encourage you to do: no matter what tools you use, please pay attention to your site or app's final output! It's never a good idea to make users pay for your technology choices.&lt;/p&gt;

</description>
      <category>ssg</category>
      <category>eleventy</category>
      <category>gatsby</category>
      <category>html</category>
    </item>
    <item>
      <title>Caches are for Copies</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Wed, 11 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/caches-are-for-copies-4i4d</link>
      <guid>https://dev.to/ambrwlsn/caches-are-for-copies-4i4d</guid>
      <description>&lt;p&gt;When someone uses their browser to visit your website, the browser fetches files from your website's server. One example could be a CSS file. Once the CSS file has been fetched, the browser can cache (store) a copy of it. This means that, as the visitor browses your site, the CSS does not need to be fetched once again from the server.&lt;/p&gt;

&lt;p&gt;The advantages of caching a file are: one less network request per page load, less use of the visitor's internet data, and faster load times. Additionally, CSS is a blocking resource. This means that while it is being fetched and loaded, other files have to wait to be loaded. So, the quicker CSS can be loaded, the quicker a visitor can enjoy your site.&lt;/p&gt;

&lt;p&gt;It is important to note once again that the &lt;strong&gt;files cached by the browser are copies&lt;/strong&gt;. This means that if a file living on your server is updated, the browser might not know about it. Therefore, a visitor might get the outdated copy of that file, rather than the updated one. The file will still load fast, as it is coming from the browser cache, but it will be outdated.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do servers manage files?
&lt;/h2&gt;

&lt;p&gt;The server you're using to serve your website determines which of your site's resources are cached, and how they are cached. There are many different server options available. For the rest of this post, I'll talk about the one hosting the post you are reading - Netlify.&lt;/p&gt;

&lt;p&gt;Netlify has default cache settings. This means that with no effort on my part, I can write my website, deploy it, and share it without needing to worry about configuring cache settings. There is a &lt;a href="https://www.netlify.com/blog/2017/02/23/better-living-through-caching/"&gt;blog post about Netlify's default cache settings entitled "Better Living Through Caching"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I briefly mentioned earlier the issue of getting an outdated file from the cache. Netlify admit that "cache invalidation is one of the hardest problems in computer science" and that they have found a way around this issue:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“max-age=0, must-revalidate, public”&lt;/strong&gt; = “please cache this content, and then do not trust your cache”. This seems a bit counterintuitive, but there’s a good reason. This favors you as a content creator — you can change any of your content in an instant.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, no visitors will be served outdated files. However, all files are re-requested on every single page load. This would be no good, except that Netlify uses "e-tags". These are hash values (long strings of unique characters). The server and browser share the e-tags. If a file changes on the server, for example a CSS file, the e-tag value changes, the browser notices, and the changed file is requested.&lt;/p&gt;

&lt;p&gt;Additionally, Netlify makes the constant checking of files faster using their CDN (content delivery network) and HTTP/2. Please look up these two things, as discussing them is beyond the scope of this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust, then verify
&lt;/h2&gt;

&lt;p&gt;It is a really nice thing in modern web development to be able to enjoy stuff done for you automatically by your browser and server. This doesn't mean that you shouldn't know how it all works, though.&lt;/p&gt;

&lt;p&gt;If a server such as Netlify offers default cache settings, it pays to look up what they are, and how they work. A server's default cache settings are unlikely to be the best for &lt;strong&gt;every&lt;/strong&gt; website.&lt;/p&gt;

&lt;p&gt;If it is necessary to change cache settings for your website, look up how to manually create your own settings. Here is a &lt;a href="https://docs.netlify.com/routing/headers/#custom-headers"&gt;post on how Netlify users can set custom cache headers&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>caching</category>
      <category>browser</category>
      <category>netlify</category>
    </item>
    <item>
      <title>Accessible Link Text</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Thu, 05 Nov 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/accessible-link-text-1ocg</link>
      <guid>https://dev.to/ambrwlsn/accessible-link-text-1ocg</guid>
      <description>&lt;p&gt;I use a bookmarklet tool called &lt;a href="https://khan.github.io/tota11y/"&gt;Tota11y&lt;/a&gt;, which gives me a quick overview of my site's accessibility. I opened it on my site's homepage and clicked "link text". The tool flagged not one, but SIX inaccessible links. Woops!&lt;/p&gt;

&lt;p&gt;The homepage, GitHub, Twitter, and LinkedIn links were all flagged for the same reason. There was no text between their opening and closing &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tags, only an SVG. Even though the tool flagged these links, I didn't have to change anything. This is because each SVG already had a &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; element, paired with a &lt;code&gt;&amp;lt;description&amp;gt;&lt;/code&gt; element to aid accessibility. A screen reader will read out the values of the title and description elements.&lt;/p&gt;

&lt;p&gt;I was a bit confused why the 'learn' and 'about' navigation links were flagged, so I checked Tota11y's source code. &lt;a href="https://github.com/Khan/tota11y/blob/master/plugins/link-text/index.js#L34-L37"&gt;The words 'learn' and 'about' are listed as stop words&lt;/a&gt;. I believe these words are singled out because they can be used alone or out of context. However, I think that both words make sense in my navigation bar. So, I ignored the warning.&lt;/p&gt;

&lt;p&gt;I was happy that I didn't have to add any new code in order to make the six flagged links accessible! If an accessibility audit flags any links on your site, and you determine that they are in fact inaccessible, there are a few things you can do.&lt;/p&gt;

&lt;p&gt;One method is to add a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; next to the existing text that is hidden (&lt;a href="https://hugogiraudel.com/2016/10/13/css-hide-and-seek/"&gt;this post describes a method for visually hiding text using CSS&lt;/a&gt;). This would make the text invisible in the UI, but a screen reader would still read it out.&lt;/p&gt;

&lt;p&gt;Another similar method is to add more descriptive (non-hidden) text to links, just as I have done for the link in the previous paragraph.&lt;/p&gt;

&lt;p&gt;The most common method is probably the &lt;code&gt;aria-label&lt;/code&gt; attribute. This is popular because the value of this attribute is read out by a screen reader even if the link already has text. For example, for my 'project' link, I could have added &lt;code&gt;aria-label="a selection of my projects"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sqKeUGTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/accessible-link-text/img/accessible-link-text.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sqKeUGTY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://amberwilson.co.uk/blog/accessible-link-text/img/accessible-link-text.png" alt="A screenshot of the VoiceOver for Chrome screen reader announcing the aria-label of the 'projects' link"&gt;&lt;/a&gt;&lt;br&gt;
    A screenshot of the VoiceOver for Chrome screen reader announcing the aria-label of the 'projects' link&lt;br&gt;
  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note 1 of 2:&lt;/strong&gt; please &lt;a href="https://amberwilson.co.uk/blog/aria-labels/"&gt;see this post on aria labels&lt;/a&gt; for the important difference between &lt;code&gt;aria-label&lt;/code&gt; and &lt;code&gt;aria-labelledby&lt;/code&gt; (hint: &lt;code&gt;aria-label&lt;/code&gt; values are not always easy for translation systems to access).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note 2 of 2:&lt;/strong&gt; try to use a variety of accessibility tools to audit your web pages. It isn't possible to catch all accessibility issues with one tool. It's also probably not possible to catch all issues with ten of them. Manual testing is highly recommended! By that I mean using a screen reader and keyboard to tab around your web pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  More resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webaim.org/techniques/hypertext/"&gt;https://webaim.org/techniques/hypertext/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA8"&gt;https://www.w3.org/WAI/WCAG21/Techniques/aria/ARIA8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.washington.edu/accessibility/links/"&gt;https://www.washington.edu/accessibility/links/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>html</category>
      <category>aria</category>
    </item>
    <item>
      <title>Make Your Own Dev Tool</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Wed, 19 Aug 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/make-your-own-dev-tool-1lho</link>
      <guid>https://dev.to/ambrwlsn/make-your-own-dev-tool-1lho</guid>
      <description>&lt;h2&gt;
  
  
  Bookmarklets - a cool personal dev tool
&lt;/h2&gt;

&lt;p&gt;I have just found out what &lt;strong&gt;bookmarklets&lt;/strong&gt; (aka &lt;strong&gt;favelets&lt;/strong&gt; - a term coined by my friend &lt;a href="http://tantek.com/"&gt;Tantek&lt;/a&gt; back in the early 2000s) are and I like 'em! So what are they?&lt;/p&gt;

&lt;p&gt;Bookmarklets run a JavaScript (JS) script against the DOM of the current document loaded in the browser. They allow a way to alter the DOM at the press of a button. They may not offer all that a browser extension or add-on can, but they can still be super handy, and also do not require downloading or installation of software.&lt;/p&gt;

&lt;p&gt;What's a nice example of a bookmarklet? Here is a &lt;a href="https://khan.github.io/tota11y/"&gt;nice accessibility bookmarklet called Tota11y&lt;/a&gt; to try out! Thanks to &lt;a href="https://adactio.com"&gt;Jeremy&lt;/a&gt; for showing me this one 👍&lt;/p&gt;

&lt;p&gt;How can a bookmarklet like Tota11y be used? First, the bookmarklet's link needs to either be saved as a bookmark, dragged into the browser's bookmark toolbar, or be available to be clicked on a web page. Second, while on a valid website, the bookmark containing the bookmarklet link should be clicked to run the bookmarklet's code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How bookmarklets work
&lt;/h2&gt;

&lt;p&gt;First you should know (or be reminded) that in a browser, bookmarks are made up of URIs (uniform resource identifiers). Each URI consists of a protocol such as &lt;code&gt;http:&lt;/code&gt;, &lt;code&gt;https:&lt;/code&gt;, &lt;code&gt;file:&lt;/code&gt;, etc., which is followed by a string. An example is &lt;code&gt;https://cat-bounce.com/&lt;/code&gt;. The &lt;code&gt;https:&lt;/code&gt; is the protocol, and the string is the domain.&lt;/p&gt;

&lt;p&gt;There is also a &lt;code&gt;javascript:&lt;/code&gt; protocol. The browser treats this protocol and its following string just like a JS application. When visiting a link that is using this JS protocol, the JS code it contains is executed. If such a link is bookmarked, it is called a bookmarklet!&lt;/p&gt;

&lt;p&gt;Something to note is that a link usually works by sending the user to a new page. To prevent a bookmarklet from triggering a page reload, the JS code that makes up the bookmarklet should return an undefined type. To do this, an anonymous, self-executing function can be used (i.e. one that does not return a value, doesn't have a name, and executes immediately).&lt;/p&gt;

&lt;p&gt;The Tota11y bookmarklet example has a link that points to a hosted JS file. This is because the link would be pretty messy if all the JS code was included as a single string within it. Below is what the Tota11y bookmarklet's link (in a beautifed format for readability) looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javascript:
  (function()
    {
      var tota11y=document.createElement('SCRIPT');
      tota11y.type='text/javascript';
      tota11y.src='https://khan.github.io/tota11y/dist/tota11y.min.js';
      document.getElementsByTagName('head')[0].appendChild(tota11y);
    }
  )();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order for a bookmarklet to point to a hosted JS file, its URI needs to contain a few things. At the very least,it should create a new script element, make this element's source (src) the hosted JS file, and then append this script to the head of the document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making your own bookmarklet
&lt;/h2&gt;

&lt;p&gt;I tried making a bookmarklet and found it was really easy to get started.&lt;/p&gt;

&lt;p&gt;I decided that I'd try something really simple that does not use a hosted JS file, but contains all the JS code in one line. So I made a bookmarklet to put a red border around each paragraph on a page. Here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;javascript: 
(function(){
    let paragraphs = document.getElementsByTagName('p');
    for (let i=0; i &amp;lt; paragraphs.length; i++){
      paragraphs[i].style.border = '3px solid red';
    }
  })();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also possible to put bookmarklet code into the &lt;code&gt;href&lt;/code&gt; of an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element, that you can then drag into your bookmarks or your bookmark toolbar. If you like, try dragging the following link into your bookmarks and clicking on the resulting bookmarklet (refresh the page to remove the effects)!&lt;/p&gt;

&lt;p&gt;&lt;a href="//javascript:%20(function()%7Blet%20paragraphs%20=%20document.getElementsByTagName('p');for%20(let%20i=0;%20i%20&amp;lt;%20paragraphs.length;%20i++)%7Bparagraphs%5Bi%5D.style.border%20=%20'3px%20solid%20red';%7D%7D)();"&gt;Paragraph border maker&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some things to note
&lt;/h2&gt;

&lt;p&gt;A browser will automatically encode any characters within a URI that it does not understand (such as quotation marks, spaces etc.) so that a bookmarklet can run smoothly.&lt;/p&gt;

&lt;p&gt;As bookmarklets contain JS, there are security concerns to be aware of when using bookmarklets created by others. However, making a few of your own bookmarklets for personal use, or using ones that have been shown to be trustworthy, is fine. More than fine - it's great!&lt;/p&gt;

&lt;p&gt;Why are bookmarklets so great? You can make a separate folder for your bookmarklets within your bookmarks folder. Then you can place this bookmarklets folder in your bookmark toolbar for your own list of easy-access, personal dev tools.&lt;/p&gt;

&lt;p&gt;Sometimes browsers may cache bookmarklet code, so changes made after it is added won't show up.&lt;/p&gt;

&lt;p&gt;Check out this &lt;a href="https://www.youtube.com/watch?v=DloHqUfPbJc"&gt;nice video on bookmarklets (Chrome-focused)&lt;/a&gt; that covers what I have written about in the "Making your own bookmarklet" section.&lt;/p&gt;

&lt;p&gt;I am completely new to bookmarklets so I may not have covered every essential thing regarding them. I really found them super easy and nice to get started on though. As usual I learn more about them as I keep trying them out!&lt;/p&gt;

</description>
      <category>bookmarklet</category>
      <category>javascript</category>
      <category>dom</category>
      <category>script</category>
    </item>
    <item>
      <title>CSS Tips for New Devs</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Mon, 04 May 2020 08:53:34 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/css-tips-for-new-devs-25mm</link>
      <guid>https://dev.to/ambrwlsn/css-tips-for-new-devs-25mm</guid>
      <description>&lt;p&gt;May the 4th be with you! &lt;/p&gt;

&lt;p&gt;If you enjoyed that greeting you'll love the nerdy stuff that is to follow. Over one evening, I wrote down some of the CSS tips I've learned over a few years of being a developer and put them in this post &lt;span&gt;😃&lt;/span&gt;. I saved my most important tip for the end of the list. Enjoy!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CSS stands for Cascading Style Sheets. This means that they are style sheets that cascade. &lt;a href="https://wattenberger.com/blog/css-cascade"&gt;Take a look at this brilliant site on the CSS cascade (that has quizzes!)&lt;/a&gt; to learn more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Various online games have been made to help people learn CSS and they are amazing to this day! &lt;a href="https://flexboxfroggy.com/"&gt;https://flexboxfroggy.com/&lt;/a&gt; for Flexbox, &lt;a href="https://cssgridgarden.com/"&gt;https://cssgridgarden.com/&lt;/a&gt; for Grid, and &lt;a href="https://flukeout.github.io/"&gt;https://flukeout.github.io/&lt;/a&gt; for CSS selectors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One part of the CSS Cascade is Specificity. HTML elements can be styled in a number of ways. Some of your styles may be overridden depending on the way you've targeted your element for styling. Writing inline styles will override any style in a stylesheet. An &lt;code&gt;id&lt;/code&gt; on an element will override a &lt;code&gt;class&lt;/code&gt;, and a &lt;code&gt;class&lt;/code&gt; will override targeting the element directly. In the spirit of the day this blog post was created, &lt;a href="https://stuffandnonsense.co.uk/archives/css_specificity_wars.html"&gt;see this post on calculating CSS specificity - Star Wars edition!&lt;/a&gt; Note that Many CSS-in-JS libraries are designed to take care of specificity issues for you by scoping styles to single files. It still absolutely pays to learn about it though!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's not a good idea to fix shortcomings in your HTML with CSS. Fix your HTML first!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are pseudo elements in HTML that can also be styled and provide handy hacks when it comes to styling elements. The most well-known are &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt;, but there are &lt;a href="https://blog.logrocket.com/a-guide-to-css-pseudo-elements/"&gt;seven pseudo elements in total&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS allows organisation of elements on web page. There are even some layout systems - the most well-known include  Grid, Flexbox, floats and table (in order from newest to oldest).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your project's browser support allows, definitely try some of the newest CSS out there, e.g. Grid. If people are too afraid to try new CSS even if it doesn't have full browser support yet, then nobody would ever try it out! Check browser support with &lt;a href="https://caniuse.com"&gt;https://caniuse.com&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Elements on a web page can be sized and spaced using quite a number of different values. There are &lt;code&gt;px&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;s, &lt;code&gt;rem&lt;/code&gt;s, &lt;code&gt;ch&lt;/code&gt;, &lt;code&gt;vw&lt;/code&gt;, &lt;code&gt;vh&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;, etc. When building more complex web pages, the interplay of element sizing or spacing values can make a big difference in the ease and maintainability of styles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For every shorthand way of writing CSS, it's more than likely that there is a long-hand way to write it. E.g. &lt;code&gt;margin: 20px 30px 10px 15px&lt;/code&gt; can be &lt;code&gt;margin-right: 30px&lt;/code&gt;, &lt;code&gt;margin-left: 15px&lt;/code&gt;, &lt;code&gt;margin-top: 20px&lt;/code&gt;, &lt;code&gt;margin-bottom: 10px&lt;/code&gt;. Writing the long-hand version can sometimes be clearer for other developers reading your CSS!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can change CSS right in your browser's dev tools (to open them, right click the browser window and choose "inspect" or "inspect element"). The great thing is, none of the styles will be saved so you can experiment here! Another great thing about the dev tools is the "computed styles" tab, because this shows you exactly what styles are currently applied to an element. This can be really helpful when it comes to debugging your CSS!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As well as computed styles, the dev tools will also show the layout styles, giving you a clear indication what margin, padding and borders are applied to an element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt; and &lt;a href="https://css-tricks.com/"&gt;CSS Tricks&lt;/a&gt; are two of your CSS-related-questions friends (but beware of outdated answers).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check the MDN docs for up-to-date CSS documentation. They even have some live playgrounds for many CSS properties - e.g. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It pays to learn about position relative and absolute. By this I mean parent elements with  &lt;code&gt;position: relative&lt;/code&gt; that have child (nested) elements with &lt;code&gt;position: absolute&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A web page tends to consist of a lot of different-sized boxes. Every element is actually viewed as a box by the browser - headings, paragraphs, spans, everything. Each box consists of 4 things - the element's content, its padding, margin and border. By default, the box model states that any border or padding you add to an element will be added on top of the element's width or height. This can be confusing or counterintuitive. Setting &lt;code&gt;box-sizing: border-box&lt;/code&gt; tells elements not to grow in width or height when border or padding is added. Instead, the content size is adjusted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t remove the default browser focus outlines unless you are &lt;em&gt;sure&lt;/em&gt; you are managing your own focus state correctly. Removing the outlines could prevent a user from being able to navigate your site using assistive technology or the keyboard. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are a lot of CSS preprocessors that allow you to generate (compile) CSS using their own unique syntax, which often offers a way to write CSS in a more organised, shorter or functional way. Beware using preprocessors, as they can be overkill for many projects, create over-sized compiled CSS, or make CSS hard to refactor in the future. Examples of preprocessors include Sass, Less, and Stylus.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS custom properties (aka CSS variables) are a way for developers to move away from CSS preprocessors and still get the benefits. They allow you to define specific values under a variable name. These variables can be used on any number of elements and if the value needs to change, it only has to be changed in one place. E.g. a variable containing a large font size such as &lt;code&gt;--fontSizeL: 150%&lt;/code&gt; can be used on many different elements like this: &lt;code&gt;font-size var(--fontSizeL)&lt;/code&gt;. If the value needs to change to &lt;code&gt;140%&lt;/code&gt;, it can be done once quickly and easily. There is no support for Internet Explorer, but polyfills exist to get around this!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS has a lot of weird quirks that you’d not think of. If you don’t know why some CSS is not doing what you want, feel free to search for the reason. Just a couple of examples include images being &lt;code&gt;display: inline-block&lt;/code&gt; so that they have an implicit bottom spacing, or that you need to set &lt;code&gt;min-width: 0&lt;/code&gt; on flex items to stop the items from growing infinitely. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS doesn't have to be overly complex. There is most often a simple solution to a styling problem. I can't tell you how many times I have over-used CSS and hacked a fragile solution together. If I had looked at the DOM (document object model - something you can see within your dev tools) and thought about what was happening properly, I could've saved myself time and many lines of unmaintainable CSS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As with all programming (and to non-believers, yes, CSS is programming &lt;span&gt;😉&lt;/span&gt;), if your head is too far into the CSS you’ve been doing, take a break and go back to it later. It can work wonders.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.cloudflare.com/the-languages-which-almost-became-css/"&gt;Check out some blog posts about the history of CSS&lt;/a&gt; and who works on it today. There is still an active CSS working group thinking about the future of CSS!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://rachelandrew.co.uk/archives/2016/09/13/why-there-is-no-css4-explaining-css-levels/"&gt;You may have heard of CSS3, but don't hold your breath for CSS4.&lt;/a&gt; The CSS working group is working on different CSS feature modules, each of which have their own 'levels' or version numbers, e.g. Flexbox version 1, or selectors level 4, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CSS expertise comes with time! While CSS is easy to start with and gives you immediate visual results, mastering it takes time and this is perfectly okay  &lt;span&gt;😃&lt;/span&gt;. It is the same for everyone.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>developer</category>
      <category>junior</category>
      <category>devtips</category>
      <category>css</category>
    </item>
    <item>
      <title>ARIA labels</title>
      <dc:creator>Amber</dc:creator>
      <pubDate>Sat, 15 Feb 2020 14:12:45 +0000</pubDate>
      <link>https://dev.to/ambrwlsn/aria-labels-fco</link>
      <guid>https://dev.to/ambrwlsn/aria-labels-fco</guid>
      <description>&lt;p&gt;Recently, I've been chatting about accessibility with two of the biggest experts on the subject. Also, the web developers I work with at &lt;a href="https://n26.com/en-eu"&gt;N26&lt;/a&gt; take accessibility very seriously. This got me interested enough to read some blog posts on the subject. Many of these posts mentioned 'landmark roles' - one of which is 'navigation'. The navigation landmark is for identifying groups of links that help users navigate around a site, or within a page. You can give an HTML element a role of navigation (please see code block below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"navigation"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Main navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- list of links --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the &lt;code&gt;nav&lt;/code&gt; element in HTML is automatically assigned &lt;code&gt;role = navigation&lt;/code&gt;, making it the best element for creating navigation sections. It is always best to use native, semantic HTML elements where possible, to avoid writing too much &lt;code&gt;ARIA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For developing the N26 web app, we use &lt;a href="https://github.com/juliettepretot/agnostic-axe"&gt;agnostic axe&lt;/a&gt; to warn us when accessibility is not up to scratch. In my console, it notified me of the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;New aXe issues
moderate: Ensures landmarks are unique https://dequeuniversity.com/rules/axe/3.5/landmark-unique?application=axeAPI
Element: &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;​…​&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;​
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I knew from my reading that this warning came from having two &lt;code&gt;nav&lt;/code&gt; elements (i.e. two elements with &lt;code&gt;role=navigation&lt;/code&gt;) on the same page. The &lt;code&gt;nav&lt;/code&gt; elements need to be distinguished from each other in some way. This is where &lt;code&gt;aria-label&lt;/code&gt; and &lt;code&gt;aria-labelledby&lt;/code&gt; come in.&lt;/p&gt;

&lt;p&gt;My first attempt at a fix involved using &lt;code&gt;aria-label&lt;/code&gt; (please see code block below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Text describing the purpose this navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;​…&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Text describing the purpose this navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;​…&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whatever value is given to &lt;code&gt;aria-label&lt;/code&gt; will be accessible to screen reader users, making it much easier to understand a HTML page's structure and purpose. The labels should provide a concise description of what each navigation element contains.&lt;/p&gt;

&lt;p&gt;After using &lt;code&gt;aria-label&lt;/code&gt;, the warning was gone from my console! Was I all done? I could have been. However, I soon learned something else. Some translation systems (e.g. Google translate) might not translate the value of &lt;code&gt;aria-label&lt;/code&gt;. Luckily, there is a way around this (please see code block below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"main-navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"main-navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Text describing the purpose this navigation
  &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"secondary-navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"secondary-navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Text describing the purpose this navigation
  &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, an &lt;code&gt;aria-labelledby&lt;/code&gt; value of a &lt;code&gt;nav&lt;/code&gt; matches the &lt;code&gt;id&lt;/code&gt; value of an &lt;code&gt;h2&lt;/code&gt;. The &lt;code&gt;h2&lt;/code&gt; contains human-readable text. It is this text that will be accessible to screen reader users. The element containing this text can also be a hidden element which exists purely for screen readers. In this case, the hidden element of course still needs text content. This method has an advantage over &lt;code&gt;aria-label&lt;/code&gt; in that the human-readable content is contained in a text node rather than an attribute. Text nodes are easier for some translation systems to access. See Heydon's &lt;a href="https://heydonworks.com/article/aria-label-is-a-xenophobe/"&gt;post&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;I learned all of this today and I am very grateful for the knowledge. Now I know it, I'll be able to apply it wherever needed in my HTML.&lt;/p&gt;

&lt;p&gt;For more information on the &lt;code&gt;nav&lt;/code&gt; element, see this &lt;a href="http://html5doctor.com/nav-element/"&gt;post&lt;/a&gt; from html5 doctor.&lt;/p&gt;

&lt;p&gt;Originally posted on my &lt;a href="https://amberwilson.co.uk/blog/aria-labels/"&gt;personal site&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>a11y</category>
    </item>
  </channel>
</rss>
