Populating Select Input with data from an API using Nextjs and typescript

RMAG news

After a series of nerve racking attempts and failures including combing through the entire internet I was finally able to achieve this feat. I shall share with you the function I currently use to populate select input using Nextjs from a Nest js api backend.

Working with asynchronous functions can be a real paid and some of the errors I encountered while attempting this included

Property ‘data’ does not exist on type ‘Promise’
Type {} is not assignable to type ReactNode
And the biggest pain of them all…. “Invalid Hook Call” Error in React: Hooks Can Only Be Called Inside of a Function Component

After literally taking days to achieve such a menial task I finally stumble upon a response on StackOverflow by Alarid (Shoutout to Alarid) that pointed me to the right direction.

This is a front end implementation only and am using the following libaries

Nextjs
Axios
Nextui

Of course this is just a “proof of concept” can can be edited to fit the libraries you are using on your nextjs project. For example you could be using the default ‘fetch’ method to pull data from an api endpoint or any other third party library like swr or tanstack

To begin make sure the libraries are installed

Create file “apiSelect” in the filepath “@/app/lib/apiSelect.tsx”

Use the code below and edit according to your need.

import axios from “axios”;
import { useState, useEffect } from “react”;
import {Select, SelectItem} from “@nextui-org/react”;

function apiSelect(url : string , lable: string, selected: string=””) {
const [options, setOptions] = useState<string[]>([]);

useEffect(() => {
async function fetchData() {
// Fetch data

const { data } = await axios.get(url);
const results: any[] = []
// Store results in the results array
data.forEach((value: any) => {
results.push({
key: value.id,
value: value.name,
});
});
// Update the options state
setOptions([
…results
])
}

// Trigger the fetch
fetchData();
}, []);

return (

<Select
label={lable}
className=”max-w-xs”
>
{(options).map((option: any) => (
<SelectItem key={option.key}>
{option.value}
</SelectItem>
))}
</Select>
);
}

export default apiSelect;

Incase you need to use authentication tokens you can include the token variable as an argument and implement using axios as shown below

import axios from “axios”;
import { useState, useEffect } from “react”;
import {Select, SelectItem} from “@nextui-org/react”;

function apiSelect(url : string , token : string, lable: string, selected: string=””) {
const [options, setOptions] = useState<string[]>([]);

useEffect(() => {
async function fetchData() {
// Fetch data
const config = {
headers: { Authorization: `Bearer ${token}` }
};
const { data } = await axios.get(url, config);
const results: any[] = []
// Store results in the results array
data.forEach((value: any) => {
results.push({
key: value.id,
value: value.name,
});
});
// Update the options state
setOptions([
…results
])
}

// Trigger the fetch
fetchData();
}, []);

return (

<Select
label={lable}
className=”max-w-xs”
>
{(options).map((option: any) => (
<SelectItem key={option.key}>
{option.value}
</SelectItem>
))}
</Select>
);

export default apiSelect;

Import the function to page.tsx file so that you can call the function.

import apiSelect from “@/app/lib/apiSelect”;

Call the function

You use the example below to call the function
With Token
{apiSelect(url, token, “Select a Role”)}

Without token

{apiSelect(url, “Select a Role”)}

Hope this helps save you lots of hours trying to figure this out…

Peace