What is the best way to convert the NextJS router.query.id to a string?

As a newcomer to TypeScript and the T3 stack (React Query / Tanstack Query), I am facing an issue with typing companyId as string. I want to avoid having to type companyId as string every time I use it in my code, but I'm struggling to find the best practice in this particular stack. Coming from plain JavaScript and useEffects for API calls, I may not be following the most efficient approach.

Note: The code snippet below is located at /pages/companies/[id].tsx

In my initial attempt, I encountered a "Rendered more hooks than during the previous render" error at "const { data: company} ...", which led me to rethink my strategy:

const CompanyPage: NextPage = () => {
  const router = useRouter()

  const companyId = router.query.id
  if (!companyId || Array.isArray(companyId)) return <div>Loading...</div> // Must check for Array.isArray due to NextJS/Typescript bug

  const { data: company } = api.companies.getSingleById.useQuery({companyId: companyId});
  if (!company ) return <div>Loading...</div>

  ...
  return (...)

I attempted another approach, but encountered issues with the type 'string | string[] | undefined' for the companyId variable sourced from router.query.id:

const CompanyPage: NextPage = () => {
  const router = useRouter()

  const companyId: string = router.query.id // Type 'string | string[] | undefined' is not assignable to type 'string'

  const { data: company } = api.companies.getSingleById.useQuery({companyId: companyId});
  if (!company ) return <div>Loading...</div>

  ...
  return (...)

UPDATE:

I have made changes to the code that seem to work, although I'm unsure if it's the ideal solution. By using this method, I only need to specify companyId as string once:

const CompanyPage: NextPage = () => {
  const router = useRouter()

  const companyId = router.query.id
  const { data: company } = api.companies.getSingleById.useQuery({companyId: companyId as string});

  if (!companyId || Array.isArray(companyId)) return <div>Loading...</div> // Must check for Array.isArray due to NextJS/Typescript bug
  if (!company ) return <div>Loading...</div>

  ...
  return (...)

ANSWER:

Credits to Fabio for providing the accepted answer.

On other routes, I typically destructure router.query into multiple variables. Here's an example based on the accepted answer:

const { companyId, locationId } = useMemo(() => ({
  companyId: router.query?.companyId?.toString() ?? "",
  locationId: router.query?.locationId?.toString() ?? "",
}), [router.query?.companyId, router.query?.locationId]);

Answer №1

To handle query parameters efficiently, you can utilize the concept of optional chaining and nullish coalescing along with the query params' toString() method. Here is a sample based on your code snippet:

const CompanyPage: NextPage = () => {
  const router = useRouter();

  // this result will be of type string
  const companyId = useMemo(() => {
    return router.query?.id?.toString?.() ?? "";
  }, [router.query?.id]);

  const { data: company } = api.companies.getSingleById.useQuery({
    companyId: companyId,
  });

  if (!company) return <div>Loading...</div>;

  return; // ...
};

The reason behind the query parameters being of type string | string[] is because having a catch-all segment would split each URL part by / and present it as an array.

An Illustrative Example

Consider having the route /some-segment/[...href] and the URL as /some-segment/200/my-post, the following scenario would apply:

  • The contents of the href query variable would be ["200", "my-post"]
  • Calling href?.toString?.() would give you /some-segment/200/my-post.

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

React, redux, and redux observable are all essential tools for developing web applications. They

I am currently working on determining the type of a promise's resolve function. Here is a snippet of the code, or you can find it on GitHub: https://github.com/Electra-project/Electra-Desktop/blob/master/src/app/header/epics.ts export function getSt ...

Using TypeScript's type casting functionality, you can easily map an enum list from C#

This is a C# enum list class that I have created: namespace MyProject.MyName { public enum MyNameList { [Description("NameOne")] NameOne, [Description("NameTwo")] NameTwo, [Description("NameThree")] NameThree ...

Updating ComboBox Selection in Angular 4

When attempting to populate a combobox with the value from a selected row, only the inputs are loading. This section is part of my page: ` <form class="form-horizontal form-label-left parsleyjs" method="post" data-parsley-priority-enabled="false" n ...

Is there a different term I can use instead of 'any' when specifying an object type in Typescript?

class ResistorColor { private colors: string[] public colorValues: {grey: number, white: number} = { grey: 8, white: 9 } } We can replace 'any' with a specific type to ensure proper typing in Typescript. How do we assign correct ...

Nextjs REACT integration for self-service registration through OKTA

Attempting to integrate the Okta SSR feature for user sign-up in my app has been challenging as I keep encountering this error message: {"errorCode":"E0000060","errorSummary":"Unsupported operation.","errorLink& ...

React encountered an issue: each child element within a list must be assigned a unique "key" prop

I am feeling a bit puzzled as to why I keep getting the error message: child in a list should have a unique "key" prop. In my SearchFilterCategory component, I have made sure to add a key for each list item using a unique id. Can you help me figu ...

Error: Unable to set value, val.set is not a defined function for this operation (Javascript

Encountering a problem while running the function val.set(key, value), resulting in a type error TypeError: val.set is not a function within the file vendor-es2015.js. Here's the simplified code snippet: import { Storage } from '@ionic/storage& ...

Standalone server does not support NextJS revalidate functionality

It appears that there is an issue with the revalidation option when using NextJS standalone server. Here is the code snippet causing the problem: return { props: { page, }, revalidate: 60, }; The NextJS configuration bei ...

The name 'Firebase' is not recognized by Typescript

Encountering typescript errors while building a project that incorporates angularfire2 and firebase. Here are the packages: "angularfire2": "^2.0.0-beta.0", "firebase": "^2.4.2", Listed below are the errors: [10:58:34] Finished 'build.html_css&apos ...

Is it possible for a service to retrieve a component's template?

I am faced with a scenario where two services (A and B) need to communicate with each other. Service A is required to build a chart based on asynchronous data received from service B, which is used in other areas so it operates independently. I attempted t ...

Insight on the process of submitting interactive forms

I'm facing a challenge that I can't seem to figure out It's a form structured in HTML like this: <button (click)="addform()">add form</button> <div class="conten-form"> <div class="MyForm" ...

Experiencing delays when loading more than 200 input fields on the screen due to

So I've been working on a project that involves having potentially unlimited input fields. However, once I add around 200 items, the performance starts to degrade significantly. You can see a demo of this issue here: (To test: Focus on the last input ...

In what ways does PROJEN streamline project configuration for infrastructure and application projects?

Exploring PROJEN and AWS CDK has raised questions for me regarding how PROJEN contributes to standardizing project configurations in the context of multiple projects or repositories. While I see its usefulness for a single project or repository through the ...

What is the best way to pass a state within a route component in react-router?

... import { useNavigate, NavigateFunction } from "react-router"; ... function Form(): JSX.Element { const navigateToCountry = (country: string) => { // Code to navigate to country page with the given country } const [selectedCount ...

Cannot compile Angular 4 Material table: Encountering unexpected closing tag

Currently, I am working on an Angular 4 Project that involves using Material. The main task at hand is to implement a table from Angular Material. However, the issue I am facing is that the table does not compile as expected. Here's the HTML code sni ...

Comparing the cost of memory and performance between using classes and interfaces

As I delve into writing TypeScript for my Angular project, one burning question arises — should I use an Interface or a Class to create my domain objects? My quest is to uncover solid data regarding the actual implications of opting for the Class route. ...

Encountering a Next.js TypeScript Build Error related to the Type 'OmitWithTag<InputFormProps, keyof PageProps, "default">' issue

`I am currently working on a project in Next Js using TypeScript. During the build process with npm run build, I encountered the following errors in the terminal: # Type 'OmitWithTag<InputFormProps, keyof PageProps, "default">' do ...

What could be the reason for the lack of impact when assigning a [dateClass] in mat-calendar?

I've been trying to customize the appearance of specific days in the mat-calendar component from Angular Material, but I'm having trouble getting it to work. I discovered the dateClass property which seemed like the right solution, but no matter ...

Please indicate the data type in Vue using Typescript

I'm currently struggling with Vue (3) + Typescript while attempting to specify a data property with a specific type. I have created a .d.ts file, but unfortunately, it hasn't helped. This is what I'm trying: import Modeler from 'bpmn-js ...

I am facing an issue with my useFetch hook causing excessive re-renders

I'm currently working on abstracting my fetch function into a custom hook for my Expo React Native application. The goal is to enable the fetch function to handle POST requests. Initially, I attempted to utilize and modify the useHook() effect availab ...