Home

Cool React scripts and functions

Let's write and explore some scripts and things that will help you in working with React. This post will be updated frequently, and some new things will be added in the future.

cover image

Let's write and explore some scripts and things that will help you in working with React. This post will be updated frequently, and some new things will be added in the future.

useEffect

We are all using useEffect in our React application. What I find annoying is that sometimes I don't need useEffect called on the initial render, but only on an update. This hook does just that. It won't trigger on the initial render, e.g when the app first loads.

You can just call this function instead of calling useEffect directly. The syntax will be the same as with useEffect.

use-effect-update.js

import React, { useEffect, useRef } from "react" const useEffectUpdate = (func, deps) => { const didMount = useRef(false) useEffect(() => { if (didMount.current) func() else didMount.current = true }, deps) } export default useEffectUpdate

withAuth

Let's say that your app has some kind of authentication. Naturally, users that are not logged in won't be able to access every page on your website.

HOC (Higher Order Component) is a perfect solution for that.

withAuth.js

const withAuth = (Component, options = {}) => ({ ...initialProps }) => { const history = useHistory(); // here you can check if the current user is logged-in and return true or false to this variable const loggedIn = false // you can send anything to the options parameter, and make your own custom logic for different things const { forbidden } = options // if user is not authenticated, and that page is forbidden then send him to "/login" page if (!loggedIn && forbidden) { history.push('/login'); return <Fragment /> } return <Component {...initialProps} user={loggedIn} /> } export default withAuth

When you have a page that you want to protect you just do this

import React from "react" import withAuth from "./withAuth" const ProtectedPage = () => { return (...) } export default withAuth(ProtectedPage, { forbidden: true })

routes

This one probably goes without saying, but as someone who made this mistake when starting, I want to share it anyway. You should always have one file with all API routes defined in there.

routes.js

export const API = { BASE: "https://api.website.com/", USERS: "users/", POSTS: "posts/" }

After registering all routes you can use them through your app like this

const data = fetch(API.BASE.USERS)

You can also destructure items from API and use them

const { BASE, USERS } = API const data = fetch(BASE.USERS)

This is useful for 2 situations.

  1. You always have all routes in one file, which is much easier to maintain than to have strings all over the project.
  2. If the route changes you have to edit it only in one place, and then the whole project will adopt a new endpoint.

useApi

This hook will make it easier for you to handle errors, loading state, and data when fetching from a REST API endpoint.

You can also pass custom triggers so that useEffect will only be called when that trigger changes, but this should do the job for start at least.

import { useEffect, useState } from 'react'; function useAPI({ url }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const fetchData = async () => { try { setLoading(true); setData(await fetch(url)); } catch (e) { setError(e); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }); return [{ data, loading, error }, fetchData]; } export default useAPI;

To use this hook you do the following

const { data, error, loading } = useAPI('https://api.website.com') if (loading) { return ( // here you can display a loader while data is getting fetched ) } if (error) { return ( // here you can display an error message ) } return ( // display data that was requested )

This is pretty useful because we know every state of our API calls without using some complicated logic or installing other clients.

Easier imports

Don't you hate when you have a relative path import that looks like this

import Button from "../../../../src/components/button"

To make this more beautiful, easier to maintain, and read, you have to create a file called jsconfig.json in the project's root folder.

After creating the file paste this configuration inside.

{ "compilerOptions": { "baseUrl": ".", "paths": { "@/components/*": ["src/components/*"], "@/styles/*": ["src/styles/*"] } }, "exclude": ["node_modules"] }

If you are using create-react-app to create your project then your configuration will look like this

{ "compilerOptions": { "baseUrl": "src" } "include": ["src"] }

Note that create-react-app doesn't support paths. Since paths are not working, if you want to import anything outside src you'll have to import it using a relative path.

// When importing components you now do this import Button from "@/components/button" // instead of import Button from "../../../../src/components/button"

or with create-react-app

// When importing components you now do this import Button from "components/button" // instead of import Button from "../../../../src/components/button"

There is no need to remember the depth of where you currently are in the project structure.

You can also make this for other things, like styles, hooks, basically anything you create in the project.

You can change the syntax of importing to whatever you like, but I find "@/components" work best for me because it helps me to visually distinct components that I made from those that are imported from external packages.

The configuration is pretty easy to read, so you can add new items effortlessly, and if you are using the same core principles and rules in your projects you can just copy-paste this file to another project, and it will work out of the box.

Get window size

In your project, you probably came to a point where you need to get window size. If you tried to use window.innerWidth you probably got an error that says ReferenceError: window is not defined. To fix this you could make a check that looks like this

if (typeof window !== "undefined") { // browser code }

but copying this on every place is a really messy job. This can be fixed by creating a hook that looks like this

import { useEffect, useState } from "react" const useWindowSize = () => { const [windowSize, setWindowSize] = useState({ width: undefined, height: undefined, }) useEffect(() => { if (typeof window !== "undefined") { function handleResize() { setWindowSize({ width: window.innerWidth, height: window.innerHeight, }) } window.addEventListener("resize", handleResize) handleResize() return () => window.removeEventListener("resize", handleResize) } }, []) return windowSize } export default useWindowSize

Using this hook is pretty easy.

const size = useWindowsSize() // accessing width and height props size.width size.height