<?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: Mike Wheaton</title>
    <description>The latest articles on DEV Community by Mike Wheaton (@mikewheaton).</description>
    <link>https://dev.to/mikewheaton</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%2F122079%2F77009ad6-44a0-4456-9421-35c9308b2435.jpg</url>
      <title>DEV Community: Mike Wheaton</title>
      <link>https://dev.to/mikewheaton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikewheaton"/>
    <language>en</language>
    <item>
      <title>Navigating with Ant Design and Reach Router</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Tue, 18 Jun 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/navigating-with-ant-design-and-reach-router-382a</link>
      <guid>https://dev.to/mikewheaton/navigating-with-ant-design-and-reach-router-382a</guid>
      <description>&lt;p&gt;&lt;a href="https://ant.design/docs/react/introduce"&gt;Ant Design&lt;/a&gt; is an open-source design system built with React. It provides a collection of well-designed, functional, and accessible components to kickstart your React project.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Menu&lt;/code&gt; component is excellent for site-wide navigation, but it wasn't immediately clear how to make this work with &lt;a href="https://reach.tech/router"&gt;Reach Router&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After some experimentation, I was able to get these working together:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Location&amp;gt;
  {props =&amp;gt; {
    return (
      &amp;lt;Menu selectedKeys={[props.location.pathname]}&amp;gt;
        &amp;lt;Menu.Item key="/courses"&amp;gt;
          &amp;lt;Link to="/courses"&amp;gt;Courses&amp;lt;/Link&amp;gt;
        &amp;lt;/Menu.Item&amp;gt;
        &amp;lt;Menu.Item key="/users"&amp;gt;
          &amp;lt;Link to="/users"&amp;gt;Users&amp;lt;/Link&amp;gt;
        &amp;lt;/Menu.Item&amp;gt;
        &amp;lt;Menu.Item key="/profile"&amp;gt;
          &amp;lt;Link to="/profile"&amp;gt;My Profile&amp;lt;/Link&amp;gt;
        &amp;lt;/Menu.Item&amp;gt;
      &amp;lt;/Menu&amp;gt;
    );
  }}
&amp;lt;/Location&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With Reach Router, any component that's a direct child of the router receives a &lt;code&gt;location&lt;/code&gt; prop that describes the user's current location within the app.&lt;/p&gt;

&lt;p&gt;In my case, the header navigation is a child of a page layout component. Rather than passing &lt;code&gt;location&lt;/code&gt; through as a prop, I've used the &lt;code&gt;Location&lt;/code&gt; component. This provides a child render prop that has access to the user's location.&lt;/p&gt;

&lt;p&gt;Ant's &lt;code&gt;Menu&lt;/code&gt; component takes any number of &lt;code&gt;Menu.Item&lt;/code&gt; children. Each of these has a &lt;code&gt;key&lt;/code&gt; to uniquely identify it, while the parent menu has &lt;code&gt;selectedKeys&lt;/code&gt; prop which takes an array of items that should be selected.&lt;/p&gt;

&lt;p&gt;By setting the key of each menu item to the corresponding path name, these can easily be matched up by passing the &lt;code&gt;selectedKeys&lt;/code&gt; prop a single-element array containing &lt;code&gt;props.location.pathname&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In short, Reach Router says "we're on /courses" and Ant's menu says "okay, I'll select the menu item with a key of /courses".&lt;/p&gt;

&lt;p&gt;This would get more complex for paths with variables (e.g. /courses/abc123/edit) but for basic navigation, this does the trick.&lt;/p&gt;

</description>
      <category>antdesign</category>
      <category>reachrouter</category>
      <category>react</category>
    </item>
    <item>
      <title>Public GraphQL queries with Hasura</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Mon, 17 Jun 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/public-graphql-queries-with-hasura-2n06</link>
      <guid>https://dev.to/mikewheaton/public-graphql-queries-with-hasura-2n06</guid>
      <description>&lt;p&gt;Lately, I've been working on a side project, &lt;a href="https://lurn.today"&gt;Lurn&lt;/a&gt;. It's an app to track the online courses you're taking and see what others are taking. Think GoodReads for courses.&lt;/p&gt;

&lt;p&gt;One of my goals with this side project is to learn how to use GraphQL to set up a backend, and I've found &lt;a href="https://hasura.io/"&gt;Hasura&lt;/a&gt; to be the fastest and most intuitive way to do so. I spent less than an hour getting it set up on Heroku, modeling out relational data, and successfully querying and modifying it with GraphQL. Wow!&lt;/p&gt;

&lt;p&gt;While I could query the data from Hasura's built-in &lt;a href="https://github.com/graphql/graphiql"&gt;GraphiQL&lt;/a&gt;, I received errors when attempting to connect to it with &lt;a href="https://github.com/apollographql/react-apollo"&gt;React Apollo&lt;/a&gt;. The endpoint rejected my request because it wasn't coming from an authenticated user. But what about apps that don't require signing in?&lt;/p&gt;

&lt;h2&gt;
  
  
  Hasura rejects unauthenticated users
&lt;/h2&gt;

&lt;p&gt;Hasura uses &lt;a href="https://docs.hasura.io/1.0/graphql/manual/auth/authorization/roles-variables.html"&gt;roles&lt;/a&gt; to determine who has permissions to read, insert, update, and delete data.&lt;/p&gt;

&lt;p&gt;It turns out that Hasura (sensibly) rejects all unauthenticated requests to the GraphQL endpoint. This prevents someone from gaining access to private data or flooding the server with requests, but it's not helpful for an app that should accessible to signed-out users.&lt;/p&gt;

&lt;p&gt;Fortunately, they provide a means of configuring a default role for unauthenticated users. Let's get that working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Hasura's unauthenticated role
&lt;/h2&gt;

&lt;p&gt;Let's change Hasura's default behavior, so that requests from unauthenticated users are assigned a default security role rather than rejected outright.&lt;/p&gt;

&lt;p&gt;Sign in to Heroku and select your Hasura app. If you're new to Hasura, &lt;a href="https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html"&gt;quick start guide&lt;/a&gt; will have you up-and-running in a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--juA530mZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/0a1d9e9ca98f56700edcf337d3262cca/47573/heroku-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--juA530mZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/0a1d9e9ca98f56700edcf337d3262cca/47573/heroku-overview.png" alt="Overview tab for a Heroku app"&gt;&lt;/a&gt;Overview tab for a Heroku app&lt;/p&gt;

&lt;p&gt;Navigate to the Settings tab and click 'Reveal Config Vars' to show your app's configuration variables. Add a new variable with a key of &lt;code&gt;HASURA_GRAPHQL_UNAUTHORIZED_ROLE&lt;/code&gt; and a value of whatever you want to call that role, such as &lt;code&gt;anonymous&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jPC7wVzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/3e4d380fe1ec285cf3e58d97ebfdbe87/47573/heroku-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jPC7wVzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/3e4d380fe1ec285cf3e58d97ebfdbe87/47573/heroku-settings.png" alt="Settings tab for a Heroku app, with config vars shown"&gt;&lt;/a&gt;Settings tab for a Heroku app, with config vars shown&lt;/p&gt;

&lt;p&gt;Click 'Open app' to launch the Hasura console and continue with the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set permissions on tables
&lt;/h2&gt;

&lt;p&gt;Select 'Data' and then choose a table you want to be publicly accessible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E9UmyR2d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/412a609dd7aab94d3c5a605ca5b1aedd/47573/hasura-table.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E9UmyR2d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/412a609dd7aab94d3c5a605ca5b1aedd/47573/hasura-table.png" alt="Hasura console with a table selected"&gt;&lt;/a&gt;Hasura console with a table selected&lt;/p&gt;

&lt;p&gt;Select the 'Permissions' tab and enter a new role. This name &lt;strong&gt;must match the value of your configuration variable&lt;/strong&gt; from earlier. In my case, it's &lt;code&gt;anonymous&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You'll see the new role added to the table. By default, permissions are blocked for all action types (insert, select, update, and delete) as indicated by the X icon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gsZ7ozVW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/9600e6fd299642a2454a4335f50ef62e/3532c/hasura-permissions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gsZ7ozVW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/9600e6fd299642a2454a4335f50ef62e/3532c/hasura-permissions.png" alt="Permissions tab for a table, with the new anonymous role added"&gt;&lt;/a&gt;Permissions tab for a table, with the new anonymous role added&lt;/p&gt;

&lt;p&gt;Click the pencil in the 'select' column. In almost all cases, you should leave the default (blocked) permissions for insert, update, and delete.&lt;/p&gt;

&lt;p&gt;Under 'Row select permissions' choose 'Without any checks'. For 'Column select permissions' choose the columns that should be available in queries. I've selected all of them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EAnBI3Sg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/12644a75b652ca33038dd092d3a6754c/2a207/hasura-select-permission.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EAnBI3Sg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.dev/static/12644a75b652ca33038dd092d3a6754c/2a207/hasura-select-permission.png" alt="Hasura permissions, granting anonymous users full access to all rows and columns"&gt;&lt;/a&gt;Hasura permissions, granting anonymous users full access to all rows and columns&lt;/p&gt;

&lt;p&gt;Click 'Save permissions' and you're all set. Repeat this process for any other tables that should be accessible to signed-out users. You can now query your GraphQL endpoint without logging in!&lt;/p&gt;

</description>
      <category>hasura</category>
      <category>graphql</category>
      <category>database</category>
      <category>apollo</category>
    </item>
    <item>
      <title>Using Functions in Themes</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Fri, 17 May 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/using-functions-in-themes-400f</link>
      <guid>https://dev.to/mikewheaton/using-functions-in-themes-400f</guid>
      <description>&lt;p&gt;As you're building a &lt;a href="styled-components-theming"&gt;Styled Components theme&lt;/a&gt;, you'll come across situations where you have a range of values. For example, a set of grays running from white to black or font sizes from tiny to gigantic.&lt;/p&gt;

&lt;p&gt;The simplest way to implement this would be to give each one an entry in the theme.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const theme = {
  neutralWhite: "#ffffff",
  neutralLighterest: "#fafafa",
  neutralLightest: "#f5f5f5",
  neutralLighter: "#eeeeee",
  neutralLight: "#e0e0e0",
  neutral: "#bdbdbd",
  neutralDark: "#9e9e9e",
  neutralDarker: "#757575",
  neutralDarkest: "#616161",
  neutralDarkerest "#424242",
  neutralAlmostBlack: "#212121"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To be fair, I've made these intentionally bad. But it's a challenge to name a set like this. Can the names communicate the relative lightness of each color? What happens &lt;del&gt;if&lt;/del&gt; when a new gray comes along and has to be added to the middle? Hello, &lt;code&gt;neutralDarkerest2&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbered values
&lt;/h2&gt;

&lt;p&gt;One approach to solving this problem is to drop names in favor of numbers. This is what &lt;a href="https://material.io/design/color/the-color-system.html#tools-for-picking-colors"&gt;Material Design&lt;/a&gt; does and what &lt;a href="https://developer.microsoft.com/en-us/fabric#/styles/web/colors/neutrals"&gt;Fabric&lt;/a&gt; recently moved to. It solves the problem of knowing how two colors relate; the larger number is darker. Adding a new color that's between 400 and 500? Name it 450 and move on to more interesting things.&lt;/p&gt;

&lt;p&gt;An even simpler approach is to name the colors 0, 1, 2, 3, etc. If a new color is needed you can shift the existing colors (e.g. 3 is now 4) and do a quick find-replace to update your app. This might not scale for design systems that span many apps, but it's a good solution for prototyping or building a small app.&lt;/p&gt;

&lt;p&gt;This could look like:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const theme = {
  neutral0: "#ffffff",
  neutral1: "#fafafa",
  neutral2: "#f5f5f5",
  ...
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While it will work fine, it's awfully repetitive. Let's see if we can do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using an array
&lt;/h2&gt;

&lt;p&gt;One great thing about theming with Styled Components is that the theme is a JavaScript object like any other. While it most often contains primitives like strings and numbers, there's nothing stopping us from putting an array or function in there.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const theme = {
  gray: [
    "#ffffff",
    "#fafafa",
    "#f5f5f5",
    ...
  ]
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's now possible to get a value from the array within a component's styles by calling &lt;code&gt;${props =&amp;gt; props.theme.gray[2]}&lt;/code&gt;. Better!&lt;/p&gt;

&lt;h2&gt;
  
  
  Calling an array from a function
&lt;/h2&gt;

&lt;p&gt;There are cases where what you really want in your theme is a function. For example, the Polished library provides a &lt;a href="https://polished.js.org/docs/#modularscale"&gt;modularScale helper&lt;/a&gt; that makes it easy to calculate a &lt;a href="https://www.modularscale.com/?1&amp;amp;em&amp;amp;1.333"&gt;relative scale&lt;/a&gt; of values.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { modularScale } from "polished";

const theme = {
  size(step) {
    return modularScale(step, "1rem");
  }
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This would be called as &lt;code&gt;${props =&amp;gt; props.theme.size(2)}&lt;/code&gt;. This is much like how our array was called above, but with parantheses instead of square brackets.&lt;/p&gt;

&lt;p&gt;While this makes sense, it can be difficult to remember which parts of the theme are arrays and which are functions. So let's write a little function that takes an index argument and returns the array at that index.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const theme = {
  gray(step) {
    return [
      "#ffffff",
      "#fafafa",
      "#f5f5f5",
      "#eeeeee",
      "#e0e0e0",
      "#bdbdbd",
      "#9e9e9e",
      "#757575",
      "#616161",
      "#424242",
      "#212121"
    ][step + 1];
  }
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can use the same syntax when referencing an array or a function in our theme.&lt;/p&gt;

&lt;p&gt;You may have noticed that it's accessing the value at &lt;code&gt;step + 1&lt;/code&gt;. Like most programming languages, JavaScript uses &lt;a href="https://blog.kevinchisholm.com/javascript/javascript-array-length-always-one-higher/"&gt;zero-based arrays&lt;/a&gt; where the first element is at position 0. This is confusing for anyone on your team who's not a developer (the design documentation is never going to start at 0 unless you insist on it) so I recommend starting at 1 instead. It's less hassle for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you haven't tried theming with Styled Components, follow along with &lt;a href="styled-components-theming"&gt;my tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Try adding a ramp of type sizes. E.g. 12px, 14px, 16px, 20px, 24px&lt;/li&gt;
&lt;li&gt;What if you wanted &lt;code&gt;myFunction(0)&lt;/code&gt; to return a value from the middle of the range instead of the first value? Could you update the function so that it's possible to call &lt;code&gt;myFunction(-2)&lt;/code&gt; for lower values?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>styledcomponents</category>
      <category>theming</category>
      <category>design</category>
      <category>styles</category>
    </item>
    <item>
      <title>Theming with Styled Components</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Sun, 12 May 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/theming-with-styled-components-19ce</link>
      <guid>https://dev.to/mikewheaton/theming-with-styled-components-19ce</guid>
      <description>&lt;p&gt;This post covers the basics of creating a &lt;a href="https://www.styled-components.com/" rel="noopener noreferrer"&gt;Styled Components&lt;/a&gt; theme.&lt;/p&gt;

&lt;p&gt;A theme contains definitions for colors, fonts, shadows, text sizes, and other visual elements that you want to use consistently. Changes to the theme are reflected everywhere, and you can even modify it at runtime to provide functionality like a dark mode toggle.&lt;/p&gt;

&lt;p&gt;I'll be using &lt;a href="https://codesandbox.io/" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt; for this tutorial. It's my go-to for creating simple proof-of-concept apps that can be easily shared. You can code along with me, or jump ahead to the &lt;a href="https://codesandbox.io/s/jjxrwl48xw" rel="noopener noreferrer"&gt;final app&lt;/a&gt; if you'd prefer.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project set up
&lt;/h2&gt;

&lt;p&gt;Create a new app on &lt;a href="https://codesandbox.io/" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt; using the React template with create-react-app.&lt;/p&gt;

&lt;p&gt;This template comes with some boilerplate we don't need. Delete the &lt;code&gt;styles.css&lt;/code&gt; file and remove its import from &lt;code&gt;index.js&lt;/code&gt;, then replace the headings with "Theming with Styled Components".&lt;/p&gt;

&lt;p&gt;Click the "Add Dependency" button and search for &lt;code&gt;styled-components&lt;/code&gt;. And just like that, we're ready to use Styled Components in our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global styles
&lt;/h2&gt;

&lt;p&gt;Styled Components is used to, well, add styles to components. However, there are situations that require defining global CSS styles that apply to the entire app rather than a specific component. These include defining custom fonts and styling the &lt;code&gt;html&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; elements.&lt;/p&gt;

&lt;p&gt;While we could add these styles in a regular CSS file, we'd miss out on the benefit of having our visual language defined in a central place. Fortunately, Styled Components provides a &lt;code&gt;createGlobalStyle&lt;/code&gt; function that can add global styles to our app. Let's create a component that will be responsible for adding this styles.&lt;/p&gt;

&lt;p&gt;Create a new file, &lt;code&gt;GlobalStyles.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createGlobalStyle } from 'styled-components';

const GlobalStyles = createGlobalStyle`
  @import url('https://fonts.googleapis.com/css?family=Poppins:400,600');

  body {
    background-color: tomato;
    font-family: Poppins, sans-serif;
  }
`;

export default GlobalStyles;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a global style that defines a custom font, applies it to the body, and sets the background color to a lovely shade of red.&lt;/p&gt;

&lt;p&gt;To apply these styles, edit &lt;code&gt;App.js&lt;/code&gt; to add our new component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import GlobalStyles from './GlobalStyles';

function App() {
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;GlobalStyles /&amp;gt;
      &amp;lt;h1&amp;gt;Theming with Styled Components&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! The font is in use and our background is very, very red.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheaton.design%2Fstatic%2F9260791668a6ab63ef71f60df1089b50%2F47573%2Fglobal-styles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheaton.design%2Fstatic%2F9260791668a6ab63ef71f60df1089b50%2F47573%2Fglobal-styles.png" alt="Screenshot of the page with a red background and Poppins font"&gt;&lt;/a&gt;Screenshot of the page with a red background and Poppins font&lt;/p&gt;

&lt;p&gt;We're off to a good start. But our global styles contain hard-coded values, which we have no way of sharing with other components or updating easily. Let's create a theme to hold these values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the theme
&lt;/h2&gt;

&lt;p&gt;A theme is a JavaScript object that all of our components will have access to via a prop. There are no requirements or limitations on its structure; we can put anything at all in there.&lt;/p&gt;

&lt;p&gt;Let's add a &lt;code&gt;theme.js&lt;/code&gt; to hold this object, since it will grow over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const theme = {
  fontSource: 'https://fonts.googleapis.com/css?family=Poppins:400,600',
  fontFamily: 'Poppins, sans-serif',
  backgroundColor: 'tomato',
};

export default theme;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This object has strings for our font source, font family name, and the background color. Our next step will be to update the &lt;code&gt;GlobalStyles&lt;/code&gt; component to use these values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the theme available
&lt;/h2&gt;

&lt;p&gt;We have a theme, but how can our components like GlobalStyles access it? While a standard import statement would work for sharing the values, it wouldn't allow us to update them at runtime to enable functionality like a dark mode.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;ThemeProvider&lt;/code&gt; comes in. It's a wrapper component that passes a theme prop to all of the components within it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ThemeProvider } from 'styled-components';

import GlobalStyles from './GlobalStyles';
import theme from './theme';

function App() {
  return (
    &amp;lt;ThemeProvider theme={theme}&amp;gt;
      &amp;lt;div className="App"&amp;gt;
        &amp;lt;GlobalStyles /&amp;gt;
        &amp;lt;h1&amp;gt;Theming with Styled Components&amp;lt;/h1&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/ThemeProvider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've imported &lt;code&gt;ThemeProvider&lt;/code&gt;, wrapped it around the entire app, and passed our theme object to it. All of our components will now have access to a &lt;code&gt;theme&lt;/code&gt; prop.&lt;/p&gt;

&lt;p&gt;Now let's test that it's working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the theme in a component
&lt;/h2&gt;

&lt;p&gt;Let's update &lt;code&gt;GlobalStyles&lt;/code&gt; to use the theme. Remember that Styled Components use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals" rel="noopener noreferrer"&gt;template strings&lt;/a&gt;. This means that at any point we can use &lt;code&gt;${}&lt;/code&gt; to embed a JavaScript expression into the string.&lt;/p&gt;

&lt;p&gt;Within that expression, we'll call a function that receives the props. We can then use an implicit return to send back a string, which will be inserted into the styles. It looks like &lt;code&gt;${props =&amp;gt; props.theme.red}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's update &lt;code&gt;GlobalStyles.js&lt;/code&gt; to use theme variables instead of hard-coded values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const GlobalStyles = createGlobalStyle`
  @import url('${props =&amp;gt; props.theme.fontSource}');

  body {
    background-color: ${props =&amp;gt; props.theme.backgroundColor};
    font-family: ${props =&amp;gt; props.theme.fontFamily};
  }
`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that and... it looks the same. That's expected, since our theme matches the previous values. Let's modify the theme so that &lt;code&gt;backgroundColor&lt;/code&gt; is set to &lt;code&gt;palegreen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheaton.design%2Fstatic%2F02587dcb37766b86ffa6c7cc34a48142%2F47573%2Ftheme-applied.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheaton.design%2Fstatic%2F02587dcb37766b86ffa6c7cc34a48142%2F47573%2Ftheme-applied.png" alt="Screenshot of the page from earlier, now with a green background"&gt;&lt;/a&gt;Screenshot of the page from earlier, now with a green background&lt;/p&gt;

&lt;p&gt;There we go! We now have a theme that's available to all of the Styled Components within our app.&lt;/p&gt;

&lt;p&gt;While the functionality is limited now, you can see how this could be scaled to include a full palette of colors, font families and sizes, and more.&lt;/p&gt;

&lt;p&gt;And because it's CSS-in-JS that's being interpreted at runtime, we can modify the theme object at any point and see those changes reflected instantly across our app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;textColor&lt;/code&gt; property to the theme and use it for the header.&lt;/li&gt;
&lt;li&gt;Instead of &lt;code&gt;backgroundColor&lt;/code&gt; always returning the same string, modify it to be a function that randomly returns one of two colors.&lt;/li&gt;
&lt;li&gt;Create a second theme object called &lt;code&gt;darkTheme&lt;/code&gt; and add a toggle that switches between it and the default theme.&lt;/li&gt;
&lt;li&gt;Check out &lt;a href="https://polished.js.org/" rel="noopener noreferrer"&gt;Polished&lt;/a&gt;, a set of functions that can be used for solving common layout problems, working with colors, and more.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>styledcomponents</category>
      <category>theming</category>
      <category>css</category>
    </item>
    <item>
      <title>Perfecting Imperfection</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Sat, 02 Feb 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/perfecting-imperfection-37lp</link>
      <guid>https://dev.to/mikewheaton/perfecting-imperfection-37lp</guid>
      <description>&lt;p&gt;Do you take pride in calling yourself a perfectionist? With cut corners all around us, surely it’s a good thing to care about quality. To sweat the details. To have high standards for what you produce. To insist on doing it right.&lt;/p&gt;

&lt;p&gt;These are worthwhile goals. But here's the thing: not only is perfectionism not the way to achieve them, it's in direct opposition to them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Perfectionism is fear in disguise.&lt;/em&gt; It’s more likely to lead to procrastination and failing to even begin, rather than sweating the details that take something from good to great.&lt;/p&gt;

&lt;p&gt;Stephen Guise makes a persuasive case for this in &lt;a href="https://www.amazon.com/dp/0996435409/"&gt;How to Be an Imperfectionist&lt;/a&gt;. He dismantles the supposed benefits of perfectionism one by one and advocates an alternate stance of &lt;em&gt;imperfectionism&lt;/em&gt;. I found myself highlighting like a first-year psych student and have included some of my favorite excerpts here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In general, the idea behind imperfectionism is to not care so much about conditions or results, and care more about what you can do right now to move forward with your identity and your life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here I'll be sharing some techniques for overcoming perfectionism, both from the book and my own practices. Let's dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get comfortable with discomfort
&lt;/h2&gt;

&lt;p&gt;When’s the last time you did something new, in front of others, that you knew you'd be terrible at? I'm betting it's “not lately”.&lt;/p&gt;

&lt;p&gt;Performing poorly in front of others, or even ourselves, is uncomfortable. But I doubt there’s any quality more predictive of success than being comfortable with that type of discomfort.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Perfectionism makes you stay home, not take chances, and procrastinate on projects; it makes you think your life is worse than it is; it keeps you from being yourself; it stresses you out; it tells you that good is bad; and it ignores the natural way in which things work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The good news is, this is a &lt;em&gt;skill you can build&lt;/em&gt; like any other.&lt;/p&gt;

&lt;p&gt;I'm far from a natural artist. Being colourblind, my art-related memories from school are mostly of the "why is the sky purple" variety. When I switched to pencil shading to avoid colour, it was "grass shouldn't be grey". I got into photography as a teenager (including some green-skinned portraits) but left the paintbrushes and pencils alone.&lt;/p&gt;

&lt;p&gt;So I surprised myself when I signed up for a painting class last year, and dreaded it so much I almost didn’t go. After a brief look at the basics, we set our easels up in a circle and started to paint. No practice and no undo button, in full view of a dozen others.&lt;/p&gt;

&lt;p&gt;It was uncomfortable and downright embarrassing at times, but I survived. As much as painting, it was a lesson in how to be imperfect in front of others. It turns out it's okay to be not-so-good, as it allows others to relax and be less self critical. We got used to making mistakes and encouraging each other to keep trying.&lt;/p&gt;

&lt;p&gt;If you're procrastinating, there's a good chance that this type of discomfort is to blame. So my advice is to pick something you’ve never done before that involves a group. It could be an art class, a team sport, improv, or anything else. &lt;em&gt;Show up and be terrible.&lt;/em&gt; Realize that it’s not going to kill you to reveal yourself as less than perfect and that there's no need to keep holding yourself back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation follows action
&lt;/h2&gt;

&lt;p&gt;One of the book's themes is that the only way to overcome the root fear of procrastination is to get moving. We've all experienced a rush of motivation that caused us to take action. It's a good feeling. But here's the secret: &lt;em&gt;action creates motivation&lt;/em&gt;. If you wait for inspiration to strike before acting, the only thing you'll make is excuses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;People who have successfully changed their lives have figured out that when you start doing something, your emotions follow suit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a few techniques you can use to achieve this action-before-motivation mindset.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cut a slice, take a bite
&lt;/h3&gt;

&lt;p&gt;Break up your project into small tasks. Then break those up. Get clear on exactly what you can do next, preferably with tasks that take 10 minutes or less. Then start.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Care less about doing it right. Care more about doing it at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By focusing on one task at a time, you avoid being overwhelmed by the project and the many ways it could turn out wrong. You take it from an ideal, imaginary state and turn it into real (if imperfect) actions that you can take now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Daily habits
&lt;/h3&gt;

&lt;p&gt;Every time you take the jump from thinking about doing something to actually doing it, you get a little better at overcoming resistance. Do this daily and you'll be surprised by how fast you improve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your best chance to reach your big dreams is through small goals in quantity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've found that the best habits are the simplest. Write for 30 minutes. Take a photo. Sketch a household object. Practice an instrument for 20 minutes. Meditate for 5. Do this every day and watch how &lt;em&gt;it adds up&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are apps for this and I know you're tempted to spend an hour researching them. Let me save you the trouble: it's best to &lt;em&gt;track the habit on a piece of paper&lt;/em&gt; stuck to your fridge or next to your desk. You'll see it all day and making a check mark with a pen is much more satisfying than tapping a button.&lt;/p&gt;

&lt;p&gt;And don't worry about being perfect (see a theme?). Missing a day is not the end of the world or an excuse to stop trying. Do the best you can and see if you can beat it next week.&lt;/p&gt;

&lt;h3&gt;
  
  
  The shitty first draft
&lt;/h3&gt;

&lt;p&gt;Creative work is 10% making and 90% editing. But before you can edit, you need something to edit. This is where what Ann Handley calls the 'shitty first draft' in &lt;a href="https://www.amazon.com/dp/B00LMB5P0G/"&gt;Everybody Writes&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;Take one of those tasks that you identified earlier, set a timer for 10 minutes, and work as fast as you can. Do everything you can to &lt;em&gt;turn off the critic in your brain&lt;/em&gt;. If you're writing, don't go back to correct typos or grammar. Don't look for the perfect word.&lt;/p&gt;

&lt;p&gt;Pay more attention to keeping your fingers moving than on writing anything coherent, nevermind eloquent. Then pat yourself on the back, take a short break, and come back to the less scary task of improving it with each revision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your brain on imperfectionism
&lt;/h2&gt;

&lt;p&gt;There are a few common thought patterns to watch out for. When you catch yourself thinking one of these, question if it's really true or if there's a more useful thought you could substitute in its place.&lt;/p&gt;

&lt;h3&gt;
  
  
  "This is going to be the best ever."
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Focus on the work, forget the results.&lt;/em&gt; The more you think about the final product in all of its glory, the harder it becomes to take imperfect action under imperfect circumstances. Which is the only action you'll ever take.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Perfectionists are driven mad or frozen in place by the chasm between desire and reality, which impairs their ability to progress and enjoy life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's more helpful to think about what you can do right now, however unimpressive it might be. Know that you'll have plenty of opportunities to improve it later.&lt;/p&gt;

&lt;h3&gt;
  
  
  "What I do is a reflection of who I am."
&lt;/h3&gt;

&lt;p&gt;You are not your work. It's easy to get attached to what we create and assume that others are using it to evaluate us. And when you believe that, it's &lt;em&gt;understandable that you're frozen in place&lt;/em&gt;, afraid to take imperfect action. You could get found out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you think people expect perfection from you, take comfort in the fact that most people don’t care what you do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oddly enough, the more you detach yourself from the work the more free you are to put your full effort into it. No one is measuring your worth by your work and neither should you.&lt;/p&gt;

&lt;h3&gt;
  
  
  "I'm almost ready to get started."
&lt;/h3&gt;

&lt;p&gt;I enjoy taking courses, reading books and articles, and soaking up new knowledge. But over time I've realized that most of what I call &lt;em&gt;preparation is procrastination&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Those who constantly seek information might have a confidence problem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's very easy to fall into a trap of believing that things would go smoothly if only you knew a bit more. But the reason they're not going well is that you insist on knowing more instead of getting started.&lt;/p&gt;

&lt;p&gt;Learn to &lt;em&gt;learn as you go&lt;/em&gt;. You need enough knowledge to take the first (imperfect) step and nothing more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now what?
&lt;/h2&gt;

&lt;p&gt;Pick something you've been putting off, identify a small first step, and &lt;em&gt;do it now&lt;/em&gt;. Close your browser. Put away your phone. Set a timer for 10 minutes and start. Focus on the task at hand rather than the end result, forget what others will think, and don't make excuses about how unprepared you are.&lt;/p&gt;

&lt;p&gt;Take a small, imperfect step forward. It gets easier with practice.&lt;/p&gt;

</description>
      <category>perfectionism</category>
      <category>tips</category>
      <category>focus</category>
    </item>
    <item>
      <title>Sorting by Created Date with GraphQL and Prisma</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Tue, 29 Jan 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/sorting-by-created-date-with-graphql-and-prisma-318c</link>
      <guid>https://dev.to/mikewheaton/sorting-by-created-date-with-graphql-and-prisma-318c</guid>
      <description>&lt;p&gt;While working on a side project with Prisma and GraphQL, I ran into a common situation. I wanted to display a list of items sorted from newest to oldest.&lt;/p&gt;

&lt;p&gt;My first idea was to add a field for the created date to the model, just like any other. This could be set in the mutation resolver when an item is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Item {
  ...
  created: DateTime!
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, I was concerned that it could be accidentally updated in the future. Given how common this requirement is, I thought there might be a better solution.&lt;/p&gt;

&lt;p&gt;Digging through the documentation, I learned of Prisma's &lt;a href="https://www.prisma.io/docs/reference/service-configuration/data-modelling-(sdl)-eiroozae8u#system-fields"&gt;system fields&lt;/a&gt;. These are read-only fields that are included in the underlying database, even when they aren't defined in the data model. They're a sort of hidden metadata for each node.&lt;/p&gt;

&lt;p&gt;And yes, it's possible to expose these to the GraphQL API by adding a 'createdAt' field with a matching directive. Don't get creative here, the names must be exact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Item {
  ...
  createdAt: DateTime! @createdAt
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's now possible to query this like any other field. Prisma generates methods to filter and sort based on this field. For my needs, &lt;code&gt;createdAt_DESC&lt;/code&gt; did the trick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;items(orderBy: createdAt_DESC) {
    id
    name
    description
    createdAt
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's all there is to it! And since this field had existed under the surface all along, it &lt;em&gt;already had data for all existing items&lt;/em&gt;. This turned out to be a huge timesaver and is a feature I'll be using, along with the 'updatedAt' system field, regularly from now on.&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>graphql</category>
      <category>database</category>
      <category>tip</category>
    </item>
    <item>
      <title>Rapid Prototypes with Google Sheets</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Sat, 12 Jan 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/rapid-prototypes-with-google-sheets-cd8</link>
      <guid>https://dev.to/mikewheaton/rapid-prototypes-with-google-sheets-cd8</guid>
      <description>&lt;p&gt;While prototyping a new web app or feature, you often need test data to fill out a view. The usual approach is to create a quick JavaScript object or JSON file, which works well enough.&lt;/p&gt;

&lt;p&gt;To a point. After you have more than a few items, it's difficult to find the one you're looking for as the object grows. Then you realize another property is needed and you'll have to add it to each item individually.&lt;/p&gt;

&lt;p&gt;Even with a small dataset, it's quickly unmaintainable.&lt;/p&gt;

&lt;p&gt;I ran into this problem while building a prototype view for &lt;a href="https://lurn.today"&gt;Lurn&lt;/a&gt;. I went in search of a spreadsheet-like interface for editing JSON files and came across a better alternative. It turns out that Google Sheets can be accessed in JSON format via a public URL. Not only does this provide a quick way to create and maintain data, it even opens up the possibility of having others edit the data like a mini-CMS or accepting user input via &lt;a href="https://www.google.com/forms/about/"&gt;Google Forms&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Want to jump ahead to the final result? Here's a &lt;a href="https://codesandbox.io/s/rmlmx2ymlq"&gt;CodeSandbox demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating and publishing your data
&lt;/h2&gt;

&lt;p&gt;Start off by going to &lt;a href="https://docs.google.com/spreadsheets/"&gt;Google Sheets&lt;/a&gt; and creating a blank spreadsheet. For each column, use a camelCase heading so that it can be easily accessed later as &lt;code&gt;row.myColumnHeader&lt;/code&gt;. You’ll also want an ID column to use as the &lt;a href="https://reactjs.org/docs/lists-and-keys.html#keys"&gt;unique key&lt;/a&gt; for each item when rendering a list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PWxkDKtB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.design/static/18930ba4ed8403c73100804ff6fb7b9a/3024d/sheet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PWxkDKtB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.design/static/18930ba4ed8403c73100804ff6fb7b9a/3024d/sheet.png" alt="Screenshot of Google Sheets with multiple columns and rows of data" title="Your spreadsheet should look something like this."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the data in place, go to the File menu and select ‘Publish to the web’. The default settings are fine, so you can go ahead and click Publish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vCExeId1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.design/static/f014890d2cb6936d1fbc3e7a10d310cf/7a138/publish.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vCExeId1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheaton.design/static/f014890d2cb6936d1fbc3e7a10d310cf/7a138/publish.png" alt="Screenshot of the Publish to the web dialog in Google Sheets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieving your data
&lt;/h2&gt;

&lt;p&gt;Now that you’ve saved your spreadsheet and have its unique key, you can point your browser to a URL in this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//spreadsheets.google.com/feeds/cells/SPREADSHEET_KEY/1/public/full?alt=json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your data is there in glorious JSON! Actually, the structure is a bit of a mess.&lt;/p&gt;

&lt;p&gt;Fortunately, there’s a project called &lt;a href="https://github.com/jsoma/tabletop"&gt;Tabletop.js&lt;/a&gt; that makes Google Sheets data easier to parse. Even better, someone has done us the favor of creating a service to run the script and return clean JSON: &lt;a href="https://spreadsheet.glitch.me/"&gt;https://spreadsheet.glitch.me/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So rather than getting the data directly from Google, use a URL in this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//spreadsheet.glitch.me/?key=SPREADSHEET_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Rendering the React component
&lt;/h2&gt;

&lt;p&gt;You're almost there! Let's get the data into your React application.&lt;/p&gt;

&lt;p&gt;In whichever component will display the data, start by adding an empty array to the state. This is where you'll place the items from the spreadsheet as they are loaded in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;items&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When you want a React component to request external data, &lt;code&gt;componentDidMount&lt;/code&gt; is the place to kick off that request. Create that method and add a fetch() that will request the data and put it into your component’s state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&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://spreadsheet.glitch.me/?key=SPREADSHEET_KEY`&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="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;items&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s2"&gt;Error fetching data:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;Now in the render method, you can get the items from state and map over them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;render&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loaded&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;Google&lt;/span&gt; &lt;span class="nx"&gt;Sheets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ol&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;items&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;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;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="sr"&gt;/ol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&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;Note that there's a loading message to display while the array is empty. The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;Fetch API&lt;/a&gt; is asynchronous, and it may take a few seconds to get the response back and re-render the component.&lt;/p&gt;

&lt;p&gt;Once the data comes back, the &lt;code&gt;items&lt;/code&gt; array will contain an object for each row of your spreadsheet. There is a corresponding property for each column, which you can access like &lt;code&gt;item.title&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s it! You have a React component pulling data from a spreadsheet. This isn’t going to scale well for a large application, but for a quick prototype you now have a much easier way to build up test data and maintain it over time.&lt;/p&gt;

&lt;p&gt;See it in action in this &lt;a href="https://codesandbox.io/s/rmlmx2ymlq"&gt;CodeSandbox demo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercises and further reading
&lt;/h2&gt;

&lt;p&gt;Want to take it to the next level?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;a href="https://www.google.com/forms/about/"&gt;Google Form&lt;/a&gt; that adds data to your spreadsheet.&lt;/li&gt;
&lt;li&gt;Add &lt;a href="https://github.com/jsoma/tabletop"&gt;Tabletop.js&lt;/a&gt; to your project for improved performance.&lt;/li&gt;
&lt;li&gt;If the request fails, display an error instead of the loading message.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>prototyping</category>
      <category>data</category>
    </item>
    <item>
      <title>Modeling (and querying) relational data with JavaScript</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Sun, 16 Dec 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/filtering-related-arrays-4kn5</link>
      <guid>https://dev.to/mikewheaton/filtering-related-arrays-4kn5</guid>
      <description>&lt;p&gt;This post describes a way of modeling relational data in JavaScript and shows how the &lt;code&gt;filter()&lt;/code&gt; and &lt;code&gt;some()&lt;/code&gt; array methods can be used to query this data. It's not intended to replace a real database, but to show how an array of objects can be filtered based on the contents of another array of objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structuring the data
&lt;/h2&gt;

&lt;p&gt;For this example, let's consider teachers and students. Each person can be represented by simple object with their person's name and a unique ID. The ID allows us to refer to a specific teacher or student, even if their name were to change in the future. Since we'll have multiple teachers and students, let's organize them in arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;teachers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Kreuger&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Amy David&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;students&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice Thompson&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bill Lemond&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ashley Jefferson&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Teachers have multiple students and students have multiple teachers. This is a many-to-many relationship, and there are several ways to model this data. One method is to create a &lt;em&gt;list of the connections between teachers and students&lt;/em&gt;. This can be referred to as an &lt;a href="https://en.wikipedia.org/wiki/Associative_entity"&gt;associative entity&lt;/a&gt; if you want to appear smart and forgot your glasses at home.&lt;/p&gt;

&lt;p&gt;Let's create a third array to describe these connections. Note that we're using the unique IDs of each teacher and student, future proofing us against name changes and allowing people to share the same name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;teachersToStudents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;teacherId&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="na"&gt;studentId&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="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;teacherId&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="na"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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="na"&gt;teacherId&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="na"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&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="na"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&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="na"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Filtering the data
&lt;/h2&gt;

&lt;p&gt;Okay, we now have three arrays describing teachers, students, and the connections between them. 🎉&lt;/p&gt;

&lt;p&gt;Let's put this to use. Our fictional application could have a profile page for each teacher with a list of their students. We're going to need a function that will take a teacher (referenced by their ID) and return an array of the students who have that teacher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns an array of students for a given teacher.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStudentsForTeacher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// @todo: Return array.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What we want to return here is a subset of the &lt;code&gt;students&lt;/code&gt; array. Lucky for us, this is exactly what the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter"&gt;filter() method&lt;/a&gt; does. It goes through the elements in an array one by one, passing each element to a function we provide. If our function returns &lt;code&gt;true&lt;/code&gt;, the element will be added to a new array.&lt;/p&gt;

&lt;p&gt;For example, if our function always returns &lt;code&gt;true&lt;/code&gt; we would get an array containing every student.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns an array of students for a given teacher.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStudentsForTeacher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;students&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;student&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&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;So what we need is a function that will return &lt;code&gt;true&lt;/code&gt; if the student is connected to the teacher and &lt;code&gt;false&lt;/code&gt; otherwise. To keep it clear let's create a second function for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns true or false, indicating whether a given teacher has a given student.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;teacherHasStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// @todo: Return true or false.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How do we answer this question? That's right, by referring to our &lt;code&gt;teachersToStudents&lt;/code&gt; array that describes all of the connections between teachers and students.&lt;/p&gt;

&lt;p&gt;We could create a loop to iterate through the array, returning &lt;code&gt;true&lt;/code&gt; if we find a match and &lt;code&gt;false&lt;/code&gt; if we reach the end. Not terrible, but there's a better way. Similar to filtering, the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some"&gt;some() method&lt;/a&gt; will iterate over the elements in an array. But instead of creating a new array, it will run each element against a test function we provide and return &lt;code&gt;true&lt;/code&gt; if at least one element passes our test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns true or false, indicating whether a given teacher has a given student.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;teacherHasStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;studentId&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;teachersToStudents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* @todo: Test function that returns true if we find a match. */&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;So all that's missing is a function that will tell us if the &lt;code&gt;teachersToStudents&lt;/code&gt; array contains an object with the teacher and student we're looking for. Here's an arrow function that compares IDs to do just that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns true if this item matches, and false otherwise.&lt;/span&gt;
&lt;span class="nx"&gt;teacherToStudent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;teacherToStudent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;teacherId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="nx"&gt;teacherToStudent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;studentId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;studentId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By passing that function to &lt;code&gt;some()&lt;/code&gt;, we now have a working function that tells us whether a given teacher has a given student!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns true or false, indicating whether a teacher has a given student.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;teacherHasStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;studentId&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;teachersToStudents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;teacherToStudent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;teacherToStudent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;teacherId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;teacherToStudent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;studentId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;studentId&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;We can update &lt;code&gt;getStudentsForTeacher()&lt;/code&gt; to use this, so that it will go through &lt;code&gt;students&lt;/code&gt; and create a new array of only those students who are associated with the specified teacher.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Returns an array of students for a given teacher.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStudentsForTeacher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&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;students&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;student&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;teacherHasStudent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;teacherId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test it out!&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="nx"&gt;getStudentsForTeacher&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="c1"&gt;// Returns 3 students.&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="nx"&gt;getStudentsForTeacher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// Returns 2 students.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Success! We've taken two arrays, described relationships between their elements using a third array, and then queried our data to get what needs to be shown on the teacher's profile page. Take a look at the &lt;a href="https://codepen.io/mikewheaton/pen/Nerxqd?editors=0012"&gt;CodePen demo&lt;/a&gt; to see how this all fits together.&lt;/p&gt;

&lt;p&gt;While this exact use case would be better handled by querying on the server-side (especially if you're dealing with thousands of records or sensitive data), these array methods are useful for other problems you're likely to encounter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exercises and further reading
&lt;/h2&gt;

&lt;p&gt;Want to get more practice with this or learn more? I'd suggest you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write a function that returns the teachers for a given student.&lt;/li&gt;
&lt;li&gt;Read up on &lt;a href="http://learnmongodbthehardway.com/schema/schemabasics/"&gt;schemas&lt;/a&gt; and find alternate ways of structuring this data.&lt;/li&gt;
&lt;li&gt;Iterate through the teachers and display a list of students for each teacher in the browser.&lt;/li&gt;
&lt;li&gt;Add an array of courses, connecting these to both teachers and students. Watch out for redundant data.&lt;/li&gt;
&lt;li&gt;Try out other common array methods like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce"&gt;reduce()&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach"&gt;forEach()&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>array</category>
      <category>filter</category>
      <category>some</category>
    </item>
    <item>
      <title>Publishing an RSS feed with Gatsby</title>
      <dc:creator>Mike Wheaton</dc:creator>
      <pubDate>Mon, 01 Jan 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/mikewheaton/publishing-an-rss-feed-with-gatsby-a3m</link>
      <guid>https://dev.to/mikewheaton/publishing-an-rss-feed-with-gatsby-a3m</guid>
      <description>&lt;h2&gt;
  
  
  Wait, what's RSS?
&lt;/h2&gt;

&lt;p&gt;In their article on how it's &lt;a href="https://www.wired.com/story/rss-readers-feedly-inoreader-old-reader/"&gt;making a comeback&lt;/a&gt;, Wired explains:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Its aim is straightforward: to make it easy to track updates to the content of a given website in a standardized format ... it can give you a comprehensive, regularly updated look at all of the content your favorite sites publish throughout the day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That standardized format is an XML file (see one for &lt;a href="https://wheaton.design/rss.xml"&gt;this site&lt;/a&gt;) that allows apps like &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt; to notify users when you post new content.&lt;/p&gt;

&lt;p&gt;Generating this for your &lt;a href="https://www.gatsbyjs.org/"&gt;Gatsby&lt;/a&gt; blog is fairly straightforward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing a feed
&lt;/h2&gt;

&lt;p&gt;Start by adding the &lt;a href="https://www.npmjs.com/package/gatsby-plugin-feed"&gt;gatsby-plugin-feed&lt;/a&gt; package to your site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save gatsby-plugin-feed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add it to the array of plugins in &lt;code&gt;gatsby-config.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins: [
  // Other plugins will already be here, don't forget the comma.
  'gatsby-plugin-feed',
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The RSS feed is only generated in production mode. You can test it by running &lt;code&gt;gatsby build &amp;amp;&amp;amp; gatsby serve&lt;/code&gt; and navigating to &lt;a href="http://localhost:9000/"&gt;http://localhost:9000/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Congratulations, you have an RSS feed! 🎉&lt;/p&gt;

&lt;p&gt;Or maybe you're staring at an ugly error message like I was. Let's get that fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customizing the feed
&lt;/h2&gt;

&lt;p&gt;By default, the plugin looks for a &lt;code&gt;slug&lt;/code&gt; field that's associated with each blog post. This is the part of the URL that represents a post, such as &lt;em&gt;/blog/the-post-title&lt;/em&gt;. It isn't generated for each post by default.&lt;/p&gt;

&lt;p&gt;While you can configure &lt;a href="https://www.gatsbyjs.org/packages/gatsby-plugin-slug/"&gt;another plugin&lt;/a&gt; to generate slugs, you can have full control over your URLs by including a &lt;code&gt;path&lt;/code&gt; in the front matter of each post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--------
path: '/blog/the-post-title'
--------

The content of your post.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, update &lt;code&gt;gatsby-config.js&lt;/code&gt; to replace the single line you added earlier (with default options) with an object containing your custom configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  resolve: `gatsby-plugin-feed`,
  options: {
    query: `
      {
        site {
          siteMetadata {
            siteUrl
          }
        }
      }
    `,
    feeds: [
      {
        serialize: ({ query: { site, allMarkdownRemark } }) =&amp;gt; {
          return allMarkdownRemark.edges.map(edge =&amp;gt; {
            return Object.assign({}, edge.node.frontmatter, {
              description: edge.node.excerpt,
              date: edge.node.frontmatter.date,
              url: site.siteMetadata.siteUrl + edge.node.frontmatter.path,
              guid: site.siteMetadata.siteUrl + edge.node.frontmatter.path,
              custom_elements: [{ 'content:encoded': edge.node.html }],
            });
          });
        },
        query: `
          {
            allMarkdownRemark(
              limit: 1000,
              sort: { order: DESC, fields: [frontmatter___date] }
            ) {
              edges {
                node {
                  excerpt
                  html
                  frontmatter {
                    date
                    path
                  }
                }
              }
            }
          }
        `,
        output: '/rss.xml',
        title: "RSS Feed",
      },
    ],
  },
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't quite as complex as it looks. Your RSS feed is generated by the &lt;code&gt;serialize()&lt;/code&gt; function. You'll see that it returns an array of posts, with an object for each post containing properties like the description and published date. Those values come from GraphQL queries of the site's metadata (top) and blog posts (bottom).&lt;/p&gt;

&lt;p&gt;There's a good chance that the code above will work for you. If not, use the &lt;a href="http://localhost:8000/___graphql"&gt;GraphiQL&lt;/a&gt; tool to test queries and explore the data you have available until you're able to complete the object that's returned for each post.&lt;/p&gt;

&lt;p&gt;While it may take a few tries to get through the errors, you'll soon have a custom configuration for your blog. This is a &lt;em&gt;set it and forget it&lt;/em&gt; task that will automatically generate an RSS feed of the latest posts when your site builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Subscribe to your blog with an app like &lt;a href="https://feedly.com/"&gt;Feedly&lt;/a&gt; to keep an eye on your RSS feed.&lt;/li&gt;
&lt;li&gt;Explore &lt;a href="https://www.npmjs.com/package/rss#itemoptions"&gt;other configuration options&lt;/a&gt; for the plugin.&lt;/li&gt;
&lt;li&gt;Learn more about &lt;a href="https://graphql.org/learn/queries/"&gt;GraphQL queries&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gatsby</category>
      <category>rss</category>
    </item>
  </channel>
</rss>
