Categories
JavaScript Next.js React

How to Set Up ESLint and Prettier in React or Next.js Projects and Format Code Automatically with Prettier with VS Code?

ESLint lets us catch errors and bad practices in our React or Next.js project easily.

And Prettier lets us format our code automatically by following some rules that are defined.

In this article, we’ll look at how to set up ESLint and Prettier in our React or Next.js project and format code automatically on save with Prettier in VS Code.

Getting Started

To get started, we’ve to install a few packages into our React or Next.js project.

To install all of them, we run:

npm i -D babel-eslint eslint eslint-config-airbnb eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks prettier

The -D flag will install the packages as dev dependencies.

Then in VS Code, we install the ESLint and Prettier extensions.

The easiest way to do this is to press Ctrl+Shift+P, and then search for ‘install extensions’ in the command search box.

Then enter the name of the extensions into the Extensions pane on the left.

Now we can configure ESLint and Prettier to search for issues and format our code.

Configure ESLint

To configure ESLint, we can add an .eslintrc.json file on the root of the project folder and add:

{
  "root": true,
  "parser": "babel-eslint",
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:react-hooks/recommended",
    "airbnb-base",
    "airbnb-base/rules/strict",
    "airbnb/rules/react",
    "plugin:prettier/recommended"
  ],
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "node": true
  },
  "parserOptions": {
    "ecmaVersion": 2021,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "plugins": [],
  "rules": {
    "react/react-in-jsx-scope": "off",
    "react/jsx-props-no-spreading": "off",
    "react/jsx-filename-extension": [
      1,
      {
        "extensions": [
          ".js",
          ".jsx"
        ]
      }
    ],
    "prettier/prettier": [
      "error",
      {},
      {
        "usePrettierrc": true
      }
    ]
  }
}

We extend the rules set we want ESLint to check in the extends section.

And in the rules section, we configure or turn off some rules.

'off' turns them off.

The rest of the rules are set to their default values.

ecmaVersion is set to 2021 to check the latest JavaScript syntax as of 2021.

Configure Prettier

To configure Prettier, we create a .prettierc file in the project folder root and add:

{
  "semi": true,
  "tabWidth": 2,
  "printWidth": 100,
  "trailingComma": "all",
  "jsxBracketSameLine": true
}

We add some rules to make Prettier format the code the way we want.

printWidth sets the max line width.

trailingComma lets Prettier add trailing commas to places where they’re allowed.

semi adds semicolons to places that should have them like end of lines.

tabWidth sets the width of the tabs in terms of spaces. 2 means 2 spaces for tabs.

jsxBracketSameLine puts the closing bracket of a multiline JSX element at the end of the last line instead of on the next line.

Also, we need to make sure that Prettier formats the code files that we write instead of package or auto-generated files.

To do this, we add a .prettierignore file to the project folder root and write:

.next
node_modules
.vscode
package.json
package-lock.json
dist

.next is the Next.js specific folder with the built files.

dist has the built files.

.vscode has VS code settings for the workspace.

Configure VS Code to Format Files on Save with Prettier and Autofix ESLint Issues

To format code with Prettier and fix ESLint issues that can be automatically fixed, we add the following to .vscode/settings.json :

{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "editor.formatOnSave": true,
  "eslint.alwaysShowStatus": true
}

We can set the default formatter to Prettier by pressing Ctrl+Shift+P, then search for ‘Format Document With’, press Enter, then select ‘Configure Default Formatter’, then we can select Prettier.

Conclusion

We can fix many code issues in React and Next,js projects and make our code neater with ESLint and Prettier.

Categories
React

Update React Query Cache with the setQueryData Method

Sometimes, we may want to update the React Query cache so that the data that’s used to render the HTML is updated on the client-side to display the latest data without fetching it from the server again.

In this article, we’ll look at how to use React Query’s setQueryData method to update the query cache data on the client-side.

Using the setQueryData Method to Update Data Cached from Making Requests

We can use the React Query’s queryClient ‘s setQueryData method to update the cached response data from making HTTP requests.

To do this, we write:

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";

import App from "./App";
export const queryClient = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </StrictMode>,
  rootElement
);

App.js

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";
import { queryClient } from "./index";

export default function App() {
  const { data } = useQuery("yesno", () => axios.get("https://yesno.wtf/api"));

const setData = () => {
    queryClient.setQueryData("yesno", (data) => {
      return {
        data: {
          ...data.data,
          answer: data.data.answer === "yes" ? "no" : "yes"
        }
      };
    });
  };

  return (
    <div>
      <button onClick={setData}>toggle</button>
      <div>{data?.data?.answer}</div>
    </div>
  );
}

In index.js , we create a new QueryClient instance that we use with the QueryClientProvider component so that we can use the React Query hooks to make requests.

Then in App.js , we use the useQuery hook to make requests.

We pass in the name of the query as the first argument.

The 2nd argument is a function that returns a promise with the HTTP request response.

The data property of the returned object has the response data.

In the setData function, we call queryClient.setQueryData with the identifier of the request we want to update as passed into useQuery ‘s first argument.

The 2nd argument is a callback that takes the cached response data for the request with the identifier in the first argument, and we return the object that will be the new value of the item that’s cached with the given identifier.

We toggle the value of the data.data.answer value from the response in setData .

And we call that when we click on the toggle button.

Therefore, we should see the data.data.answer value toggle between 'yes' and 'no' when we click the toggle button.

This is because we update the query cache data entry for the request with the identifier passed into the first argument of sertQueryData to what we want on the client-side.

Conclusion

We can update the cached response data on the client side with React Query’s query client’s setQueryData method.

Categories
React

Add a Diff Display into a React App with the jsdiff Library

Sometimes, we may want to show the difference between 2 pieces of text to the user.

We can do this easily with the jsdiff library.

In this article, we’ll look at how we can use the jsdiff library with React.

Installation

We can install the library by running:

npm install diff --save

Add the Diff Display

We can add the diff display into our React app by writing the following:

import React from "react";
const Diff = require("diff");

const one = "beep boop";
const other = "beep boob blah";

const diff = Diff.diffChars(one, other);
export default function App() {
  return (
    <div className="App">
      {diff.map((part) => {
        const color = part.added ? "green" : part.removed ? "red" : "grey";
        return <span style={{ color }}>{part.value}</span>;
      })}
    </div>
  );
}

The one and other strings are what we want to diff.

We call Diff.diffChars with both of them to create the diff array.

Then we call diff.map to map the diffed parts to span elements.

part.added is true when the part is in the 2nd string but not the first.

part.removed is true when the part isn’t in the 2nd string but it’s in the first.

part.value has the value of the part.

Now we should see the comparisons displayed.

The display will show the 2nd string which is the other string, with the parts that are added to the first string in green and the parts that are removed from the first string in red.

We can show diffed JSON objects ith the diffJson method.

To use it, we write:

import React from "react";
const Diff = require("diff");

const one = { foo: "bar", bar: "baz" };
const other = { foo: "bar", bar: "bar" };

const diff = Diff.diffJson(one, other);
export default function App() {
  return (
    <div className="App">
      {diff.map((part) => {
        const color = part.added ? "green" : part.removed ? "red" : "grey";
        return <span style={{ color }}>{part.value}</span>;
      })}
    </div>
  );
}

It’ll show the properties that are added, removed, or stay the same with the same colors that we set.

Other methods include the diffTrimmedLines method to compare text line by line ignoring leading and trailing whitespace.

diffSentences compares 2 blocks of text sentence by sentence.

diffCss compares 2 CSS tokens.

diffArrays compare the entries of 2 arrays with the === operator.

They all return an array of objects with the same properties as in the examples.

Conclusion

We can use the jsdiff library with React to show text diffs to users easily.

Categories
React

How to Add a Menu with Active Item Highlighting with React?

Sometimes we want to add a menu with the active menu item highlighted in our React app.

In this article, we’ll look at how to add a menu with active items highlighting with React.

Add a Menu with Active Item Highlighting

To add a menu with the active item highlighting in our React app, we can listen to the mouseenter and mouseleave events.

We add the highlight to the item that’s hovered over when the mouseenter event is emitted.

And when the mouseleave event is emitted, we clear the highlights on all items.

We set the onMouseEnter prop to the mouseenter event handler and set the onMouseLeave prop to the mouseleave event handler.

To do this, we write:

import { useState } from "react";

export default function App() {
  const [hoveredItem, setHoveredItem] = useState("");
  const resetHover = () => setHoveredItem("");

  return (
    <div className="App">
      <style>
        {`
          .hovered {
            color: red;
          }
        `}
      </style>
      <ul>
        <li
          className={hoveredItem === "apple" ? "hovered" : undefined}
          onMouseEnter={() => setHoveredItem("apple")}
          onMouseLeave={resetHover}
        >
          apple
        </li>
        <li
          className={hoveredItem === "orange" ? "hovered" : undefined}
          onMouseEnter={() => setHoveredItem("apple")}
          onMouseLeave={resetHover}
        >
          orange
        </li>
        <li
          className={hoveredItem === "grape" ? "hovered" : undefined}
          onMouseEnter={() => setHoveredItem("apple")}
          onMouseLeave={resetHover}
        >
          grape
        </li>
        <li
          className={hoveredItem === "pear" ? "hovered" : undefined}
          onMouseEnter={() => setHoveredItem("apple")}
          onMouseLeave={resetHover}
        >
          pear
        </li>
        <li
          className={hoveredItem === "banana" ? "hovered" : undefined}
          onMouseEnter={() => setHoveredItem("apple")}
          onMouseLeave={resetHover}
        >
          banana
        </li>
      </ul>
    </div>
  );
}

We have the hoveredItem state to keep track of which item is highlighted.

And we have the resetHover function to call setHoveredItem function with an empty string to reset hoveredItem ‘s value.

Below that, we have the style tag with the styles for the hovered class, which has the styles that are applied when we highlight an item.

Then we have the li elements with the className applied dynamically.

We apply the hovered class when the hoveredItem value is the same as the value that we pass into the setHoveredItem function.

The onMouseEnter prop is set to a function that sets the hoveredItem state.

And the onMouseLeave prop is set to the resetHover function to reset the hoveredItem value when our mouse leaves the li element.

Now when we hover over an item, we should see the item that our mouse hovered over becomes red.

When our mouse leaves the item, then the items turn back to black.

Conclusion

We can add a menu with active items highlighting with React easily.

To do this, we just listen to the mouseenter and mouseleave events and applies the class to add the highlight accordingly.

Categories
React

How to Add a Scroll Event Listener to a Scrollable Element in a React Component?

Sometimes, we may want to add a scroll event listener to a scrollable element in a React component.

In this article, we’ll look at how to add a scroll event listener to a scrollable element in a React component.

Add a Scroll Event Listener to a Scrollable Element in a React Component

We can pass in a callback function as the value of the onScroll prop of the scrollable element.

For instance, we can write:

import React, { useState, useRef } from "react";

export default function App() {
  const prevScrollY = useRef(0);
  const [goingUp, setGoingUp] = useState(false);

  const onScroll = (e) => {
    const currentScrollY = e.target.scrollTop;
    if (prevScrollY.current < currentScrollY && goingUp) {
      setGoingUp(false);
    }
    if (prevScrollY.current > currentScrollY && !goingUp) {
      setGoingUp(true);
    }
    prevScrollY.current = currentScrollY;
    console.log(goingUp, currentScrollY);
  };

  return (
    <div onScroll={onScroll} style={{ height: 300, overflowY: "scroll" }}>
      {Array(50)
        .fill("foo")
        .map((f, i) => {
          return <p key={i}>{f}</p>;
        })}
    </div>
  );
}

We have the prevScrollY ref to store the previous value of window.scrollY so we can compare with the current scrollY value to see if we’re scrolling up or down.

Then we define the goingUp state to let us track whether we’re scrolling up or down.

We get the e.target.scrollTop value to get the current vertical scroll position.

Then we compare the currentScrollY against the prevScrollY.current value.

If currentScrollY is bigger than the prevScrollY.current and goinUp is true , then we’re going down.

So we call setGoingUp with false to to indicate that we’re scrolling down.

On the other hand, if we have prevScrollY.current bigger than currentScrollY and goinUp is false , then we call setGoingUp to true to indicate that we’re scrolling up.

Then we set prevScrollY.current to currentScrollY to store the previous vertical scroll position

And then we login the value of goingUp and currentScrollY .

Below that, we add our scrollable div with the onScroll prop set to the onScroll function.

We set the height to a finite number so that we can make the div scrollable.

And we render the content of the div inside that.

Now when we scroll up and down, we see the goingUp and currentScrollY values logged.

Conclusion

We can watch the scroll position of a scrollable element by passing in a scroll event handler to the onScroll prop.