-2

I am currently busy working on a personal project with a dashboard using NextJS, which I believe allows me to learn NextJS and the fundementals of typescript. I am trying to work out how to set a welcome message if a response sent back from the server is set to True, I did manage to code this in, but I got cannot set headers after they are sent to the client.

My entire code file for the dashboard is the following snippet:

import styles from "./index.module.css";
import { type NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import { signIn, signOut, useSession } from "next-auth/react";
import Image from 'react-bootstrap/Image'
import Router from "next/router";
import { useEffect, useState } from "react";
import { library } from '@fortawesome/fontawesome-svg-core'
import { faHouse, fas, faServer } from '@fortawesome/free-solid-svg-icons'
import "@fortawesome/fontawesome-svg-core/styles.css"; 
import { Offline, Online } from "react-detect-offline";
import { config } from "@fortawesome/fontawesome-svg-core";
// Tell Font Awesome to skip adding the CSS automatically 
// since it's already imported above
config.autoAddCss = false; 

{/* The following line can be included in your src/index.js or _App.js file*/}
import 'bootstrap/dist/css/bootstrap.min.css';

library.add(fas, faServer, faHouse)

// import the icons you need
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'


const Protected: NextPage = () => {
    const { status, data } = useSession()
    const { data: sessionData2 } = useSession();
    
    useEffect(() => {
      if (status === "unauthenticated") Router.replace("/auth/signin");
    }, [status]);
  
    // const isBreakpoint = useMediaQuery(768)
    //     return (
    //     <div>
    //     { isBreakpoint ? (
    //         <div>
    //         <HamburgerMenu />
    //         </div>
    //     ) : (
    //         <div>
    //             <FullMenu />
    //         </div>
    //     )
    if (status === "authenticated")  
            return (
            <><Navbar bg="dark" expand="lg" variant="dark" className="justify-content-end flex-grow-1 pe-3">
                    <Container>
                        <Navbar.Brand href="#home" style={{ fontSize: '25px' }}><strong>Litika.</strong> </Navbar.Brand>
                        {/* <Navbar.Toggle aria-controls="basic-navbar-nav" /> */}
                        <Navbar.Collapse id="basic-navbar-nav" className={styles.rightNavbar}>
                            <Nav className={styles.rightNavbar}> 
                                <Nav.Link href="#home" className={styles.body}><FontAwesomeIcon icon={faHouse} /></Nav.Link>
                                <Nav.Link href="#link" className={styles.body}>Link</Nav.Link>
                                <NavDropdown className={styles.body} title={<Image
                                    src={sessionData2 ? `https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_640.png` : 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_640.png'}
                                    roundedCircle
                                    style={{ width: '30px' }} />}
                                    id="basic-nav-dropdown">
                                    <NavDropdown.Item href="#action/3.1" onClick={sessionData2 ? () => void signOut() : () => void signIn()}>
                                        {sessionData2 ? "Sign out" : "Sign in"}
                                    </NavDropdown.Item>
                                    <NavDropdown.Item href="#action/3.2">
                                        Another action
                                    </NavDropdown.Item>
                                    <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
                                    <NavDropdown.Divider />
                                    <NavDropdown.Item href="#action/3.4">
                                        Separated link
                                    </NavDropdown.Item>
                                </NavDropdown>
                            </Nav>
                        </Navbar.Collapse>
                    </Container>
                </Navbar>
                <div className={styles.connectivityStatus}>
                    <br></br>
                    <div className={styles.connectivityStatusBox}>
                        <Online> You are connected to the internet.</Online>
                        <Offline> You are not connected to the internet.</Offline>                
                    </div>
                    <WelcomeContainer />
                </div>
                <main className={styles.main}>
                <h1 className={styles.title}>
                       Litika.     </h1>  
                        <div className={styles.container}>
                            
                            <div className={styles.cardRow}> 
                            <div className={styles.card}>
                                <h1 className={styles.cardTitle}><FontAwesomeIcon icon={faServer} /> HELLO!</h1>
                                <p className={styles.cardText}>How are you? I am under the water.</p>
                            </div>
                            </div>
                            
                        </div>
                    </main>
                    <main className={styles.main2}>
                        <div className={styles.container}>
                        </div>
                    </main>
                </>
    );
    return (
        <>
    <main className={styles.main}>
                        <div className={styles.container}>
                            <h1 className={styles.title}>
                                Loading the Dashboard.
                            </h1>
                            
                        </div>
                    </main>
    <main className={styles.main2}>
        <div className={styles.container}>
            <h1 className={styles.title}>
            </h1>
            
        </div>
    </main>
        </>
    );

};

export default Protected;

const WelcomeContainer: React.FC = () => {
    const { data: sessionData } = useSession();

    var [welcomeMessage, setWelcomeMessage] = useState(null);

    const payload = JSON.stringify({
        email: sessionData.user?.email,
    });
      
    fetch('/api/userService/isuserwelcome', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: payload
    })
    .then(response => response.json())
    .then(data => {
        console.log(data);
        if (data === true) {
            setWelcomeMessage(
                <div className={styles.welcomeContainer}>
                    <h1>Welcome to the Los pollos hermanos family.</h1>
                </div>
            );
        }
    })
    .catch(error => {
        console.error(error);
    });

    return (
        <>
            {welcomeMessage}
        </>
    );
};

The code for the IsUserWelcome API Route is the following:

import type { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const { email } = req.body;

    const cliresponse = await prisma.user.findFirst({
      where: {
        email,
    },
    });
    console.log(cliresponse.newUser)
    if (cliresponse.newUser == true) {
        res.status(200).json(cliresponse.newUser)
    }
    res.status(200).json({ cliresponse });
  } catch (err) {
    console.log(err)
    res.status(500).json({ error: err});
  }
}

I have identified the issue to be coming from the WelcomeContainer Functional Component and do understand that NextJS & React are dynamic, which will lead to updates through the DOM. However, I haven't really tried anything yet to fix this issue because nothing from doing a simple Google search could lead me to fix this issue, so any guidance & help will be appreciated!

The parts that are different in this question is that it pertains to react and NextJS in general, not express.

Ruler
  • 85
  • 9
  • The problem isn't your front end code, it's in your endpoint function. – BrendanOtherwhyz Feb 10 '23 at 03:14
  • I apologize, but I cannot find where the problem is located, could you please point it out to me? – Ruler Feb 10 '23 at 03:27
  • Sorry. This is your front end code right? I'm talking about your back end code. Can you attach the code for the function that's serving this url `/api/userService/isuserwelcome'`? – BrendanOtherwhyz Feb 10 '23 at 03:29
  • The hint is the word `client` in `cannot set headers after they are sent to the client.` – BrendanOtherwhyz Feb 10 '23 at 03:30
  • I have currently edited the post to include the code that is serving the API URL. – Ruler Feb 10 '23 at 03:34
  • Does this answer your question? [Error: Can't set headers after they are sent to the client](https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client) – Phil Feb 10 '23 at 03:37
  • I have already gotten my issue resolved. Thanks for helping though! – Ruler Feb 10 '23 at 03:47

1 Answers1

0

You are sending a response twice, after a response is send you should return from the function.

import type { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const { email } = req.body;

    const cliresponse = await prisma.user.findFirst({
      where: {
        email,
    },
    });
    console.log(cliresponse.newUser)
    if (cliresponse.newUser == true) {
        res.status(200).json(cliresponse.newUser)
        return; // you need to return here so the code below doesn't get executed
    }
    res.status(200).json({ cliresponse });
  } catch (err) {
    console.log(err)
    res.status(500).json({ error: err});
  }
}
  • It works now, I overlooked the problem being the API Route, thank you very much! – Ruler Feb 10 '23 at 03:38
  • Although I do have another question on how to make the Functional Component from continuously hitting the API route & only hit it every couple of seconds. It's becoming a RAM hog for me. – Ruler Feb 10 '23 at 03:51
  • This is a separate question, so please create a new question for that – BrendanOtherwhyz Feb 10 '23 at 03:54
  • I apologize, but stack overflow isn't allowing me to make new questions. – Ruler Feb 10 '23 at 03:57