Next.js Discord

Discord Forum

build errors, using wrong approach? Code works fine when running it in dev btw

Answered
Waterman posted this in #help-forum
Open in Discord
Avatar
For someone to look at this I will just share the parts of my code that I think is making these errors

I think there is an easy fix for the one who just knows if this is wrong or not,
But first of all, here is the error:

./app/(routes)/produkter/ny/page.tsx
26:41  Error: React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks
*******More messages here of the same type*********
44:3  Error: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks

./app/(routes)/produkter/[...]/page.tsx
48:20  Error: React Hook "usePathname" is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks

*******More messages here of the same type*********

135:3  Error: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.  react-hooks/rules-of-hooks



here is some code that I think is making errors during the build process:

if (value === "") {
    return (
      <div className="min-h-screen w-full flex flex-col items-center justify-center gap-8">
        <div className="flex flex-col gap-4 items-center justify-center p-4 bg-[#222222] text-white rounded-md">
          <Image
            width={200}
            height={200}
            src={produkt?.bilder[0] || vercelImg}

/more code.... and then:/
if (value === "redigera") {
    return (
      <div className="p-4">
        <div className="">
          <Button
            className="md:w-fit w-full"
            variant="glowPrim"
            onClick={() => {

So I have more of these ^^^^ but ofcourse I also have some useeffect hooks and usestate hooks further up in the code, I will share this code down below in the next message
Answered by Waterman
So the solution I found now, was that I used an if statement before declaring the useState and useEffect
View full answer

4 Replies

Avatar
so I will now send all of my code that comes before the one I shared above, except the imports etc...

const [value, setValue] = useState("");

  const [produkt, setProdukt] = useState<ProduktProps | null>(null);

  const [goToProducts, setGoToProducts] = useState(false);

  const [namn, setNamn] = useState(produkt?.namn || "");
  const [url, setUrl] = useState(produkt?.url || "");
  const [ovrigtnamn, setOvrigtnamn] = useState(produkt?.ovrigtnamn || "");
  const [beskrivning, setBeskrivning] = useState(produkt?.beskrivning || "");
  const [sku, setSku] = useState(produkt?.sku || "");
  const [rea, setRea] = useState(produkt?.rea || 0);
  const [lager, setLager] = useState(produkt?.lager || 0);
  const [kategori, setKategori] = useState(produkt?.kategori || []);
  const [pris, setPris] = useState(produkt?.pris || 0);
  const [bilder, setBilder] = useState(produkt?.bilder || []);
  const [aktiv, setAktiv] = useState(produkt?.aktiv || false);

  if (goToProducts) {
    return redirect("/produkter");
  }

  const pathname = usePathname();
  const pathnameSplit = pathname.split("/");
  const id = pathnameSplit[pathnameSplit.length - 1];

  useEffect(() => {
    async function getProducts() {
      const res = await axios.get("/api/produkt?id=" + id);
      console.log(res.data);
      setProdukt(res.data);
    }
    getProducts();
  }, []);

  useEffect(() => {
    if (value === "radera") {
      const deleteProduct = async () => {
        const res = await axios.delete("/api/produkt?id=" + id);
        console.log(res.data);
        setGoToProducts(true);
      };
      deleteProduct();
    }
  }, [value, id]);
more code:
  useEffect(() => {
    if (produkt) {
      setNamn(produkt.namn || "");
      setUrl(produkt.url || "");
      setOvrigtnamn(produkt.ovrigtnamn || "");
      setBeskrivning(produkt.beskrivning || "");
      setSku(produkt.sku || "");
      setRea(produkt.rea || 0);
      setLager(produkt.lager || 0);
      setKategori(produkt.kategori || []);
      setPris(produkt.pris || 0);
      setBilder(produkt.bilder || []);
      setAktiv(produkt.aktiv || false);
    }
  }, [produkt]);
async function handleSaveProduct(e: React.FormEvent): Promise<void> {
    e.preventDefault();

    const updatedProduct = {
      namn,
      url,
      ovrigtnamn,
      beskrivning,
      sku,
      rea,
      lager,
      kategori,
      pris,
      bilder,
      aktiv,
    };

    const _id = id;

     await axios.put(`/api/produkt`, { ...updatedProduct, _id });

    setGoToProducts(true);
  }

  const [isUploading, setIsUploading] = useState(false);

  async function uploadImage(ev: React.ChangeEvent<HTMLInputElement>) {
    const files = ev.target?.files;
    if (files && files.length > 0) {
      setIsUploading(true);
      const data = new FormData();
      for (let i = 0; i < files.length; i++) {
        data.append("file", files[i]);
      }
      const res = await axios.post("/api/upload", data);
      setTimeout(() => {
        setBilder((oldBilder: string[]) => {
          return [...oldBilder, ...res.data.links];
        });
        setIsUploading(false);
      }, 1500);
    }
  }

  const [options, setOptions] = useState([{ value: "test", label: "test" }]);

  useEffect(() => {
    const fetchCategories = async () => {
      try {
        const response = await fetch("/api/kategori");

        const categories = await response.json();

        const formattedOptions = (categories as any[]).map((cat) => ({
          value: cat.namn,
          label: cat.namn,
        }));

        setOptions(formattedOptions);
      } catch (error) {
        console.error("Error fetching categories:", error);
      }
    };

    fetchCategories();
  }, []);
Avatar
So the solution I found now, was that I used an if statement before declaring the useState and useEffect
Answer