Categories
Next.js

Next.js — CSS-in-JS, Fast Refresh, and Environment Variables

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at how to style pages, use fast refresh, and add environment variables with Next.js.

Less and Stylus Support

Next.js support Less and Stylus for styling.

To add support for it, we install the @zeit/next-less and @zeit/next-stylus plugins.

CSS-in-JS

We can also use any CSS-in-JS solution for styling our Next.js app.

For example, we can add inline styles:

function Hello() {
  return <p style={{ color: 'blue' }}>hello world</p>
}

export default Hello

We can also use styled-jsx to put CSS in our JavaScript files.

It comes with Next.js.

For example, we can write:

function Hello() {
  return <div>
    <style jsx>{`
        p {
          color: blue;
        }
        div {
          background: red;
        }
        @media (max-width: 600px) {
          div {
            background: blue;
          }
        }
      `}</style>
    <style global jsx>{`
        body {
          background: lightgray;
        }
      `}</style>
    <p>hello world</p>
  </div>
}

export default Hello

We add style tags which contains local and global styles.

Global styles have the global prop and local ones don’t.

Fast Refresh

Fast refresh is a Next.js feature that makes development easier.

It gives us instant feedback on edits made to our React components.

It’s enabled by default on Next 9.4 or later.

This feature lets make edits visible without losing component state.

It’ll reload the component if we edit a component.

If we edit something that that’s not a component but it’s used by them, then both files will be refreshed.

If a file that’s imported by files outside of the refresh tree, then fast refresh will do a full reload.

When any runtime errors are encountered, then we’ll see an overlay with the error displayed.

If we added error boundaries to our app, then they’ll retry rendering on the next edit.

If there’re any hooks, then their state will be updated when a fast refresh happens.

Static File Serving

Next.js apps can have static files.

We just have to put them inside the public folder.

For example, we can write:

function Hello() {
  return <div>
    <img src="/kitten.jpg" alt="kitten" />
  </div>
}

export default Hello

given that kitten.jpg is in the public folder.

We’ll see the kitten picture displayed.

We shouldn’t change the name of the public folder since it’s the only folder that can be used to serve static assets.

Environment Variables

We can load environment variables from an .env.local file.

For example, we can create an .env.local file by writing:

API_KEY=...

And then we can create a page that uses the API_KEY environment variable with:

function Photos({ data }) {
  return <p>{JSON.stringify(data)}</p>
}

export async function getServerSideProps() {
  const headers = new Headers();
  headers.append('Authorization', process.env.API_KEY);
  const res = await fetch(`https://api.pexels.com/v1/search?query=people`, {
    method: 'GET',
    headers,
    mode: 'cors',
    cache: 'default',
  })
  const data = await res.json()
  return { props: { data } }
}

export default Photos

We access our environment variable with the process.env object.

These environment variables are only available in the Node.js environment.

Conclusion

Next.js 9.4 or later comes with the fast refresh feature to make development more convenient.

Also, Next.js comes with CSS-in-JS support.

We can also use environment variables in our apps.

Categories
Next.js

Next.js — Client-Side Navigation and API Routes

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at routing with Next.js.

Client-Side Navigation

In addition to routing on server-side, we can also do client-side navigation with Next.js.

For example, we can write:

pages/links.js

import { useRouter } from 'next/router'

function Links() {
  const router = useRouter()

  return (
    <ul>
      <li>
        <span onClick={() => router.push('/foo')}>foo</span>
      </li>
      <li>
        <span onClick={() => router.push('/bar')}>bar</span>
      </li>
    </ul>
  )
}

export default Links

pages/foo.js

import Links from './links';

function Foo() {
  return <div>
    <Links />
    <p>foo</p>
  </div>
}

export default Foo

pages/bar.js

import Links from './links';

function Bar() {
  return <div>
    <Links />
    <p>bar</p>
  </div>
}
export default Bar

We have the pages/links.js file with spans that runs the router.push method on click.

The router object comes from Next.js’s useRouter hook.

Shallow Routing

Shallow routing lets us change the URL without running data fetching methods like getServerSideProps , getStaticProps , and getInitialProps again.

We get the updated pathname and query via the router object.

For example, we can write:

pages/count.js

import { useEffect } from 'react'
import { useRouter } from 'next/router'

function Count() {
  const router = useRouter()

  useEffect(() => {
    router.push('/count?count=10', undefined, { shallow: true })
  }, [])

  useEffect(() => {
  }, [router.query.count])

  return <p>{router.query.count}</p>
}

export default Count

to add a Count component with a useEffect hook that calls router.push to add a query string to the URL.

shallow: true means that we enable shallow routing.

We should see 10 displayed since router.query.count is 10 as we see from the query string when we go to http://localhost:3000/count.

Shallow routing only works for same page URL changes.

So if we have:

router.push('/?count=10', '/about?count=10', { shallow: true })

then the about page would be loaded from scratch.

API Routes

We can use API routes to build an API with Next.js.

To do that , we can put JavaScrtipt files inside the pages/api folder.

Then the files inside would be mapped to the /api/* URLs.

For example, we can write:

pages/api/hello.js

export default (req, res) => {
  res.statusCode = 200
  res.json({ name: 'hello world' })
}

req has the requests data and res is an object we can use to create our response.

We set the response status code with res.statusCode and we create our JSON response with the res.json method.

Now when we make a request to http://localhost:3000/api/hello with any HTTP verb, we’ll see:

{
  "name": "hello world"
}

returned.

To handle different HTTP methods, in an API route, we can use the req.method property.

For example, we can write:

export default (req, res) => {
  res.statusCode = 200
  res.json({ name: 'hello world', method: req.method })
}

Now when we make a PUT request to http://localhost:3000/api/hello, we get:

{
    "name": "hello world",
    "method": "PUT"
}

returned.

API routes don’t specify CORS headers, so we can only make these requests if the request originates from the same origin as the API route.

Conclusion

We can make API routes with Next.js.

Navigation can be done from the client side with the useRouter hook.

Categories
Next.js

Getting Started with Next.js

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at how to get started with Next.js.

Getting Started

We can create our Next.js project with its provided command-line program.

To create the project, we just run:

npx create-next-app

or:

yarn create next-app

to create our project.

Then to start the dev server, we run:

npm run dev

Then we go to http://localhost:3000/ and our app.

Now we can create a component in the pages folder to add our page.

We go into the pages folder, create an hello.js file and add:

function Hello() {
  return <div>hello world</div>
}

export default Hello

to it.

We’ve to remember to export the component so that it’ll be rendered.

Then we can go to http://localhost:3000/hello and see our page.

Next.js does routing automatically by the file name so we don’t have to worry about that.

Pages with Dynamic Routes

If we want to create pages with dynamic routes, we just put them in the folder structure and the URLs will follow the same structure.

For example, we can create a posts folder and create our files.

We create 1.js in pages/posts and write:

function Hello() {
  return <div>hello 1</div>
}

export default Hello

Likewise, we create 2.js in the same folder and write:

function Hello() {
  return <div>hello 2</div>
}

export default Hello

Then when we go to http://localhost:3000/posts/1 and http://localhost:3000/posts/2, we’ll see hello 1 and hello 2 respectively.

Pre-rendering

Next.js pre-renders every page by default.

The HTML for each page are created in advanced.

This is better for performance and SEO than rendering it on the client-side.

The pages only come with the JavaScript it needs to load so that it loads faster.

There’re 2 forms of pre-rendering.

One is static generation and the other is server-side rendering.

Static generation means that HTML is generated at build time and are reused on each request.

Since it reuses the pages, it’ll be the fastest way to render pages, so this is the recommended option.

The other option is server-side rendering, which renders the HTML no each request.

We can choose between the 2 types of rendering.

Static Generation with Data

We can generate pages statically with data.

To do this, we can write:

pages/yesno.js

function YesNo({ data }) {
  return <p>{data.answer}</p>
}

export async function getStaticProps() {
  const res = await fetch('https://yesno.wtf/api')
  const data = await res.json()
  return {
    props: {
      data,
    },
  }
}

export default YesNo

We created a new component file with the YesNo component.

The getStaticProps function gets the data asynchronously from an API.

Then we return the resolved value by return an object with the data in the props property.

Then we can get that data from the props in the YesNo component.

And in the JSX, we displayed the data.

Conclusion

We can create pages with Next.js that displays static content or content from an API easily.

Categories
Vue

Getting Started with Storybook for Vue

Storybook is an open-source tool for developing UI components in isolation.

It works with React, Vue, Angular, and other frameworks.

In this article, we’ll look at how to add Storybook to our Vue project and create our components.

Install Storybook

To get started with Storybook, we create a new Vue project with Vue CLI.

We run npx vue create . in an empty project folder to create a Vue project.

Then we follow the instructions to complete the process.

Once we did that, we run:

npx sb init

to create the Storybook project.

Once we did that, we run:

npm run storybook

in our Vue project folder to run Storybook in our Vue project.

Then we should see the Storybook screen in our browser.

It has a collection of links to the Storybook components and we can preview them.

Story

Once we have Storybook set up, we can create our stories.

A story is a collection of components that we can preview in Storybook.

The preview includes the possible states and props that it can take and what it looks like with them.

It also includes the docs.

In the preview screen, we can edit the props and preview what it’ll look like with them in the Controls tab.

Write Stories

We can put stories in the strotries folder.

To start, we add a .js or .ts file for our story.

For example, we can create a button.

In the stories folder, we add a Button.vue file to create our Storybook component:

<template>
  <button type="button" :class="classes" @click="onClick" :style="style">{{ label }}</button>
</template>

<script>
import './button.css';

export default {
  name: 'my-button',

props: {
    label: {
      type: String,
      required: true,
    },
    primary: {
      type: Boolean,
      default: false,
    },
    size: {
      type: String,
      default: 'medium',
      validator (value) {
        return ['small', 'medium', 'large'].includes(value);
      },
    },
    backgroundColor: {
      type: String,
    },
  },

  computed: {
    classes() {
      return {
        'button': true,
        'button-primary': this.primary,
        [`button-${this.size}`]: true,
      };
    },
    style() {
      return {
        backgroundColor: this.backgroundColor,
      };
    },
  },

  methods: {
    onClick() {
      this.$emit('onClick');
    },
  },
};
</script>

Our component takes a few props to let us style our button.

label is for the label text.

primary is a boolean for changing the colors of the button.

size is the size of the button.

backgroundColor is the background color.

We imported button.css in the same folder, which has:

.button {
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
}
.button-primary {
  color: white;
  background-color: lightblue;
}
.button-small {
  font-size: 12px;
}
.button-medium {
  font-size: 16px;
}
.button-large {
  font-size: 20px;
}

To make it show in Storybook, we’ve to add a Button.stories.js file with the following code:

import MyButton from './Button.vue';

export default {
  title: 'Example/Button',
  component: MyButton,
  argTypes: {
    backgroundColor: { control: 'color' },
    size: { control: { type: 'select', options: ['small', 'medium', 'large'] } },
  },
};

const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { MyButton },
  template: '<my-button @onClick="onClick" v-bind="$props" />',
});

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};

export const Large = Template.bind({});
Large.args = {
  size: 'large',
  label: 'Button',
};

export const Small = Template.bind({});
Small.args = {
  size: 'small',
  label: 'Button',
};

All the exported items will be shown by Storybook.

The default export has the title, component, and argTypes .

title is the title shown in Storybook.

component is the component we want to preview.

argTypes define the controls that we can set to change prop values.

The names are the same as the prop names.

We also have the Template object that sets the props to the argType keys.

components with the component to preview.

template for the component to preview.

v-bind='$props' passes all props to the my-button component.

Then 3 exports at the bottom define the preset styles that we want to show the button with.

We pass in some args and they’ll be set as props.

Now we should see the component displayed in the sidebar.

Conclusion

We can create a Storybook with Vue by creating a Vue CLI project and then add Storybook code to it.

Then we can add our components and stories.

Categories
JavaScript

Introduction to the Location Object

To take us to different locations in JavaScript, we can use the location global object.

In this article, we’ll look at how to use it to get and set URLs.

Properties of the Location Object

The location object is a property of window , which is the global object.

It has a few properties.

The origin property is the URL where the link is clicked to get to the current page.

The protocol is the proto of the URL, so it’s ‘http://’ or 'https://' for most pages,

host is the hostname part of the URL, so it’s something like example.com .

hostname is the same as host if the port is 80. Otherwise, host has the port number but hostname doesn’t.

port is the port number. If it’s 80, then it’ll be an empty string.

Otherwise, it’ll be a string of the port number.

pathname is the path after the hostname.

search has the query string, so it’s something like '?page=1' .

hash has the part after the pound sign, so it’s something like '#foo' .

href hs the whole URL, so it’s something like 'http://example.com/foo?page=1' .

We can assign values to any of the properties described above.

So we can set the href property:

location.href = 'http://example.com'

Then we’ll go to 'http://example.com' .

The only property that’s read-only is the location.origin property.

Methods of the Location Object

We can call assign to assign to navigate to a given URL.

So we can call it by writing:

location.assign('http://example.com');

The replace navigates to a given URL and removes the current page from the session history.

So it does the same thing as assign but the history won’t show the current URL.

reload reloads the current page.

toString returns the URL.

Page Redirection

We can do page redirection by setting location.href or call the assign or replace methods.

For example, we can write:

location.href = 'https://example.com';

or:

location.assign('https://example.com');

or:

location.replace('https://example.com');

The first 2 will keep the current page in the session history, while replace will overwrite the session history with the new URL.

Conclusion

In the browser, we can use the location object to set the URL and get the parts of the URL.

Also, we can call its methods to call change the URL.