Error Encountered in Nextjs 14: Cookies Unreachable in axiosInstance or apiService Files

After transitioning to Nextjs from React, I found the architecture of Nextjs to be quite different and confusing. In my current project, I am attempting to authorize API CRUD operations using a token stored in a cookie. However, when trying to retrieve the token inside the axiosInstance, it is returning undefined.

axiosInstance.ts

import axios from 'axios';
import Cookies from 'js-cookie';

const axiosInstance = axios.create({
  baseURL: process.env.NEXT_PUBLIC_CLIENT_URL,
  withCredentials: true,
});

axiosInstance.interceptors.request.use((config) => {
  const token = Cookies.get('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default axiosInstance;

This is the function for getting staff data from the API.

staffAPIServices.ts

import axiosInstance from '../../axios/axiosInstance';
// Get Staff
export const getStaff = async () => {
  try {
    const response = await axiosInstance.get('admin/staff');
    if (response.data.status) {
      return response?.data?.data?.staff;
    }
  } catch (err: unknown) {
    const errorString = err instanceof Error ? err.message : 'Unknown Error';
    return err;
  }
};

To display the staff data in a table, I have implemented the following code:

import clsx from 'clsx';
import { getStaff } from '@/app/utils/services/staff/staffAPIServices';


export default async function StaffTable({
  query,
  page,
}: {
  query: string;
  page: number;
}) {

  interface ItemType {
    id: number;
    name: string;
    email: string;
    email_verified_at: string;
    created_at: string;
    updated_at: string;
    deleted_at: string;
  }

  const staff = await getStaff();

  return (
    <div className="mt-6 flow-root">
      <div className="inline-block min-w-full align-middle">
        <div className="rounded-lg bg-gray-50 p-2 md:pt-0">
          <table className="hidden min-w-full text-gray-900 md:table">
            <thead className="rounded-lg text-left text-sm font-normal">
              <tr>
                <th scope="col" className="px-4 py-5 font-medium sm:pl-6">
                  ID
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Name
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Email
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Date
                </th>
                <th scope="col" className="px-2 py-5 font-medium">
                  Status
                </th>
                <th scope="col" className="relative py-3 pl-6 pr-3">
                  <span className="sr-only">Edit</span>
                </th>
              </tr>
            </thead>
            <tbody className="bg-white">
              {Array.isArray(staff) && 
                staff.map((item: ItemType) => (
                  <tr
                    key={item.id}
                    className="w-full border-b py-4 text-sm last-of-type:border-none [&:first-child>td:first-child]:rounded-tl-lg [&:first-child>td:last-child]:rounded-tr-lg [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg"
                  >
                    <td className="whitespace-nowrap py-3 pl-6 pr-3">
                      <p>{item.id}</p>
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">{item.name}</td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.email}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.created_at}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      <span
                        className={clsx(
                          'flex items-center justify-center rounded-full px-4 py-1',
                          {
                            'bg-red-500 text-white': item.deleted_at === null,
                            'bg-green-500 text-white': item.deleted_at !== null,
                          },
                        )}
                      >
                        {item.deleted_at ? 'Active' : 'Inactive'}
                      </span>
                    </td>
                  </tr>
                ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

I have attempted the following solutions:

  1. Directly inputting the token string as Bearer fake-token-12312312 (which worked), but this goes against DRY principles and I have numerous API functions.
  2. Transforming axiosInstance.ts and staffAPIServices.ts into client-side components using 'use client'. This approach did not yield the desired result.
  3. In reference to a related question on StackOverflow, someone suggested fetching the cookie within the page by converting it into a client-side component. However, Nextjs raised an issue stating "Prevent client components from being async functions."

Answer №1

I managed to find a solution by transforming the StaffTable into a client component, which enabled the API to successfully retrieve the stored token cookie and receive response data. However, I am unsure if this is considered a professional Nextjs approach.

'use client';

import { useEffect, useState } from 'react'; 
import clsx from 'clsx'; 
import { getStaff } from '@/app/utils/services/staff/staffAPIServices';

export default function StaffTable({   query,   page, }: {   query: string;   page: number; }) {   interface ItemType {
    id: number;
    name: string;
    email: string;
    email_verified_at: string;
    created_at: string;
    updated_at: string;
    deleted_at: string;   }

  const [staff, setStaff] = useState<ItemType[]>([]);   const [loading, setLoading] = useState(true);   const [error, setError] = useState('');

  useEffect(() => {
    const fetchStaff = async () => {
      try {
        const staffData = await getStaff();
        setStaff(staffData);
        setLoading(false);
      } catch (error) {
        setError('Error fetching staff data');
        setLoading(false);
      }
    };

    fetchStaff();   }, []);

  if (loading) {
    return <p>Loading...</p>;   }

  if (error) {
    return <p>{error}</p>;   }

  return (
    <div className="mt-6 flow-root">
      <div className="inline-block min-w-full align-middle">
        <div className="rounded-lg bg-gray-50 p-2 md:pt-0">
          <table className="hidden min-w-full text-gray-900 md:table">
            <thead className="rounded-lg text-left text-sm font-normal">
              <tr>
                <th scope="col" className="px-4 py-5 font-medium sm:pl-6">
                  ID
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Name
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Email
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Date
                </th>
                <th scope="col" className="px-2 py-5 font-medium">
                  Status
                </th>
                <th scope="col" className="relative py-3 pl-6 pr-3">
                  <span className="sr-only">Edit</span>
                </th>
              </tr>
            </thead>
            <tbody className="bg-white">
              {Array.isArray(staff) &&
                staff.map((item: ItemType) => (
                  <tr
                    key={item.id}
                    className="w-full border-b py-4 text-sm last-of-type:border-none [&:first-child>td:first-child]:rounded-tl-lg [&:first-child>td:last-child]:rounded-tr-lg [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg"
                  >
                    <td className="whitespace-nowrap py-3 pl-6 pr-3">
                      <p>{item.id}</p>
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">{item.name}</td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.email}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.created_at}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      <span
                        className={clsx(
                          'flex items-center justify-center rounded-full px-4 py-1',
                          {
                            'bg-red-500 text-white': item.deleted_at === null,
                            'bg-green-500 text-white': item.deleted_at !== null,
                          },
                        )}
                      >
                        {item.deleted_at ? 'Active' : 'Inactive'}
                      </span>
                    </td>
                  </tr>
                ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>   
); 
}

Answer №2

axiosInstance.ts and staffAPIServices.ts are not React Components so including 'use client' will have no effect. To make use of these functions on the client side, the components that utilize them need to be made client-side, not the functions themselves.

If these components are indeed client-side and you have confirmed that they are running in a browser environment (by adding some console.log statements and observing if they print to the terminal or browser console), you can then inspect the cookie itself:

Cookies may have HttpOnly attributes set, which would prevent access to them on the client side. You can verify this by checking the application tab in Chrome Developer Tools: https://i.sstatic.net/OjrRd.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using jQuery and Ajax to efficiently handle the retrieval of large files while browsing

I have some large text files that are potentially multiple GB in size, and I am looking for a way to view them within a div element. The idea is to make an AJAX request for a more manageable chunk of the file, have the AJAX script (preferably in PHP) inte ...

Angular 6 tutorial: Creating a dynamic side navigation bar with swipe and drag functionality using Angular Material/Bootstrap

I am currently working on implementing a vertical swipeable/stretchable side nav-bar with angular-material in angular 6. However, I have encountered an issue with mouse interactions for stretching the nav-bar. Below is the code snippet: Here is the HTML c ...

Incorporate a typescript library into your Angular application

Recently, I added a text editor called Jodit to my angular application and faced some challenges in integrating it smoothly. The steps I followed were: npm install --save jodit Inserted "node_modules/jodit/build/jodit.min.js" in angular.json's bui ...

What is the best way to pass route props using the <router-link> component?

Check out the button below that links to a specific route: <router-link class="q-pa-md" :to="{ name: 'Edit'}" id="item.id"> <q-btn outline>Edit</q-btn> </router-link> Take a look at my router se ...

Difficulty fetching data on the frontend with Typescript, React, Vite, and Express

I'm currently working on an app utilizing Express in the backend and React in the frontend with typescript. This is also my first time using Vite to build the frontend. While my APIs are functioning correctly, I am facing difficulties fetching data on ...

Immersive bootstrap 4 card featuring dynamic highcharts

I am faced with the challenge of making highcharts charts adjust their height when displayed in full screen mode within bootstrap cards. Even though I received assistance from "daniel_s" in creating an example for panels, the transition to cards and additi ...

Having trouble getting the new dynamic bootstrap card to function properly

I'm struggling to add a new bootstrap card to my page. Every time I try to insert it, the card doesn't show up. Here is the code snippet: Show a new bootstrap card if a record exists <div class="row"> <button type="button" ...

React: "The function is not toISOString"

I am currently working on a Todo List project using Next.js. As part of the functionality, I am trying to implement a due date feature. However, when I make a post request, I encounter the following error: Unhandled Runtime Error TypeError: dueDate.toISOSt ...

Integrating Gesture Handling in Leaflet JS for two-finger scrolling enforcement

Have you ever noticed that when you're using a mobile device and scrolling down a webpage with a Google map, the map goes dark and prompts you to "Use two fingers to move the map"? https://i.stack.imgur.com/4HD1M.jpg I am interested in incorporating ...

Guide on Generating a Response Object in Node.js/Express

My current situation involves needing to execute a res.redirect('/signin'), however, I have already utilized my res object for a res.render. Is there a feasible method for me to create a new Response Object (res) so that I can carry out the redi ...

Saving logs to a file or variable in Ionic using Angularjs

I am currently developing a new project using Ionic (based on AngularJs) and so far everything is functioning as expected. For debugging purposes, I have implemented a method where every 'Function call' (every step) is output to the console via ...

Using Javascript to create bold text within a string

I have noticed that many people are asking about this issue, but it seems like a clear and simple answer is hard to come by. Currently, I am working with Vue and trying to display text from an object in a component. My goal is to highlight the price port ...

I am interested in utilizing angular 4 ng2-ui/map with places-auto-complete functionality that is restricted to a specific country

Check out my code snippet below: <input class="form-control" placeholder="Pickup Location" places-auto-complete (place_changed)="pickupChanged($event)" formControlName="pickup_location" [types]="['geocode']" /> I am trying to figure out ...

Issue encountered when attempting to utilize filters with strapi V4 graphql and nextjs, functionality not working

Currently, I am using strapi V4 along with the graphql extension. Everything works fine when I use filters with variables in the graphql Playground. query getOrdersFilterList($searchstring: String!) { orders(filters: { customer: { contains: $searchstring } ...

jQuery tooltip anchored to the left side of the screen, ignoring all attempts to adjust its position

I have a jQuery tooltip that is supposed to hover over the table header, but it is displaying on the far left side of my screen with no formatting - just black text. I have attempted to use the placement and position jQuery attributes, but they do not seem ...

What is the best way to configure TypeScript for recognizing import paths that include RequireJS plugins such as "plugin!./path/to/foo"?

Let's say we have the following scenario: import template from 'hb!./foo.hb' Is there a way to inform TypeScript about this import statement (or simply ignore it, knowing that RequireJS will take care of it)? ...

Steps to develop a sub-route specifically for a single word

Take a look at this code: {path : 'recipes', component:RecipesComponent, children:[ {path:':id', component:RecipeDetailComponent}, {path:':new', component:NewRecipeComponent } ]}, No matter which link you use: h ...

Transferring documents using JavaScript

I have been using the following method to upload files to my Laravel backend: setFile(id, e) { let self = this; let reader = new FileReader(); reader.readAsDataURL(e.target.files[0]); reader. ...

A Guide to Retrieving the First Child Element's Text with Jquery and a Class Selector

I want to extract the text from the first child small element inside a dynamically generated div. The structure looks like this: <div class="NDateCount" style="display:inline-block"> <!--Issue to solve--> <small ...

Exploring the process of using querySelector() to locate specific class and div IDs in JavaScript code

My objective is to make the id="myDropdownTop" trigger the corresponding drop-down menu. The problem lies in my script code, particularly the final line: ("div.dropdown-content").classList.toggle("show"); does not seem to be functioning correctly. <!D ...