Home > Software design >  Fetching data when Modal loads in Next.js
Fetching data when Modal loads in Next.js

Time:10-08

I'm building some functionality in my application where a user can add a new project to a timesheet application.

The way I' trying to do this is by creating a Modal that contains a form. In the form, I have a Select field that should be populated with all existing users in the database. Thus, I tried to use the useEffect hook to fetch the data from an 'api' and then populate the Select field with the user names.

Below the code examples:

Main screen with button to open the Modal

import MainScreen from '../../../components/mainscreen';
import Table from '../../../components/table';

const ProjectOverview = () => {
  return(
    <MainScreen>
      <Table />
    </MainScreen>
  );
};

export default ProjectOverview;

Table.js

import ProjectCols from '../data/projectcols';
import DataTable from 'react-data-table-component';
import React, { useState } from 'react';
import Modal from './modal';
import ProjectForm from './forms/projectform';

const Table = () => {
  const [showModal, setShowModal] = useState(false);

  const data = [
    {
      id: 1,
      project: 'Test Project A',
      client: 'Customer A',
      pm: 'John Doe',
      active: true
    },
    {
      id: 2,
      project: 'Test Project B',
      client: 'Customer B',
      pm: 'Jane Doe',
      active: false
    }
  ];

  return (
    <div id='overview' className="bg-slate-100 h-screen w-full overflow-y-auto">
      <div className='flex justify-end h-20 w-3/4 m-auto'>
        <div className='flex space-x-2 h-full'>
          <button type='button' onClick={() => setShowModal(true)} className='self-center inline-block px-6 py-2.5 bg-green-500 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-green-600 hover:shadow-lg focus:bg-green-600 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-green-700 active:shadow-lg transition duration-150 ease-in-out'>Add</button>
        </div>
      </div>
      <div className='w-3/4 m-auto'>
        <DataTable 
          columns={ProjectCols} 
          data={data} //This will need to be retrieved from the database
          direction="auto"
          fixedHeaderScrollHeight="300px"
          pagination
          responsive
        />
      </div>
      <Modal onClose={() => setShowModal(false)} show={showModal} title='Create a new project'>
        <ProjectForm />
      </Modal>
    </div>
  );
};

export default Table;

Modal.js

const Modal = ({ show, onClose, children, title }) => {

  const handleCloseClick = (e) => {
    e.preventDefault();
    onClose();
  };

  return ( show ? (
    <div tabIndex="-1" aria-hidden="true" className="overflow-y-auto fixed inset-0 bg-gray-600 bg-opacity-50 z-50 h-full w-full md:inset-0 md:h-full">
      <div className="relative top-20 p-4 mx-auto w-1/2 h-full md:h-auto">
        <div className="relative bg-white rounded-lg shadow dark:bg-gray-700">
          <button type="button" onClick={handleCloseClick} className="absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white">
            <svg aria-hidden="true" className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd"></path></svg>
            <span className="sr-only">Close modal</span>
          </button>
          <div className="py-6 px-6 lg:px-8">
            <h3 className="mb-4 text-xl font-medium text-center text-gray-900 dark:text-white">{title}</h3>
            {children}
          </div>
        </div>
      </div>
    </div> 
  ) : null
  );
};

export default Modal;

select.js

const Select = ({ label, register, options }) => {
  return (
    <div className="flex items-center mt-5">
      <label className="w-1/4 block text-sm font-medium text-gray-900 dark:text-white">{label}</label>
      <select {...register('projectManager')} className="bg-gray-50 w-3/4 m-auto border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
        {options.map(option => {
          return (
            <option key={option.id} value={option.id}>{option.name}</option>
          );
        }
        )}
      </select>
    </div>
  );
};

export default Select;

EDIT; Forgot to add the code that doesn't seem te work

projectform.js

import { useForm } from 'react-hook-form';
import Input from '../form-components/input';
import Button from '../form-components/button';
import Select from '../form-components/select';
import { useState, useEffect } from 'react';

const ProjectForm = () => {
  const { register, handleSubmit } = useForm();
  const [data, setData] = useState(null);

  useEffect(() => {
    console.log('trigger');
    fetch('http://localhost:3000/api/user')
      .then((data) => {
        setData(data);
      });
  }, []);

  //   const users = [
  //     {id: 1, name: 'Piet Snot'},
  //     {id: 2, name: 'Stefano Gandolfo'}
  //   ];

  return (
    <form className='flex flex-col justify-around' onSubmit={handleSubmit((data) => console.log(data))}>
      <Input label='Project Name' register={register} required />
      <Select label='Project Manager' options={data} register={register}/>
      <Button name='Create' type='submit' onClick={() => console.log('Test')} />
    </form>
  );
};

export default ProjectForm;

I've been trying to get this thing solved over the past 2 days but just can't seem to find the issue.. All help would be greatly appreciated!

Cheers!

CodePudding user response:

The fetch returns a Response object, and you need to run .json() (in this case) on it to get the data.

So

useEffect(() => {
    console.log('trigger');
    fetch('http://localhost:3000/api/user')
      .then(response => response.json())
      .then((data) => {
        setData(data);
      });
  }, []);
  • Related