Next.js Discord

Discord Forum

using useState with function calls function when set to another one

Answered
SharpieMaster posted this in #help-forum
Open in Discord
Avatar
"use client";
import React, { useState, type ReactNode, ReactElement, type FC } from "react";

const Modal = ({
  children,
}: {
  children: [
    ReactElement<typeof ModalContainer>,
    ReactElement<typeof ModalTrigger>,
  ];
}) => {
  const [hello, setHello] = useState<() => void>(() => {
    console.log("old");
  });

  const [ModalContainer, ModalTrigger] = children;
  return (
    <>
      <ModalContainerBackend setHello={setHello}>
        {ModalContainer}
      </ModalContainerBackend>
      <ModalTriggerBackend hello={hello}>{ModalTrigger}</ModalTriggerBackend>
    </>
  );
};

export const ModalContainer: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal container">{children}</div>;
};

export const ModalTrigger: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal trigger">{children}</div>;
};

const ModalContainerBackend: FC<{
  setHello: (hello: () => void) => void;
  children: ReactNode;
}> = ({ setHello, children }) => {
  return (
    <div
      className="bg-zinc-200 p-4"
      onClick={() => setHello(() => console.log("new"))} // When clicked, console log "new" for some reason
    >
      {children}
    </div>
  );
};

const ModalTriggerBackend: FC<{
  hello: () => void;
  children: ReactNode;
}> = ({ hello, children }) => {
  return (
    <div
      onClick={() => console.log(hello)} // Logs undefined, even though it has a default value of () => console.log("old")
      className="border p-4"
    >
      {children}
    </div>
  );
};

export default Modal;
Answered by SharpieMaster
Solved,

"use client";
import React, { useState, type ReactNode, ReactElement, type FC } from "react";

const Modal = ({
  children,
}: {
  children: [
    ReactElement<typeof ModalContainer>,
    ReactElement<typeof ModalTrigger>,
  ];
}) => {
  const [hello, setHello] = useState<{ fn: () => void }>({
    fn: () => {
      console.log("old");
    },
  });

  const [ModalContainer, ModalTrigger] = children;
  return (
    <>
      <ModalContainerBackend setHello={setHello}>
        {ModalContainer}
      </ModalContainerBackend>
      <ModalTriggerBackend hello={hello}>{ModalTrigger}</ModalTriggerBackend>
    </>
  );
};

export const ModalContainer: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal container">{children}</div>;
};

export const ModalTrigger: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal trigger">{children}</div>;
};

const ModalContainerBackend: FC<{
  setHello: (value: { fn: () => void }) => void;
  children: ReactNode;
}> = ({ setHello, children }) => {
  return (
    <div
      className="bg-zinc-200 p-4"
      onClick={() => setHello({ fn: () => console.log("new") })}
    >
      {children}
    </div>
  );
};

const ModalTriggerBackend: FC<{
  hello: { fn: () => void };
  children: ReactNode;
}> = ({ hello, children }) => {
  return (
    <div onClick={hello.fn} className="border p-4">
      {children}
    </div>
  );
};

export default Modal;


Putting a function in an object fixed the issue, the container was logging "new" because with useState() you can make an expression for your new value useState((prev) => prev + 1), but I was using console.log("new") so it was running it, and set the new value to undefined.
View full answer

2 Replies

Avatar
Im trying to create a Modal component and I ran into some strange behavior
        <Modal>
          <ModalContainer>Smoething</ModalContainer>
          <ModalTrigger>Trigger</ModalTrigger>
        </Modal>

This is how I use it on the page,
and whenever I press the ModalContainer it logs "new"
and when I press ModalTrigger it logs undefined even though it has a default value,
I'd really appreciate it if someone could help me with this

Thanks
Avatar
Solved,

"use client";
import React, { useState, type ReactNode, ReactElement, type FC } from "react";

const Modal = ({
  children,
}: {
  children: [
    ReactElement<typeof ModalContainer>,
    ReactElement<typeof ModalTrigger>,
  ];
}) => {
  const [hello, setHello] = useState<{ fn: () => void }>({
    fn: () => {
      console.log("old");
    },
  });

  const [ModalContainer, ModalTrigger] = children;
  return (
    <>
      <ModalContainerBackend setHello={setHello}>
        {ModalContainer}
      </ModalContainerBackend>
      <ModalTriggerBackend hello={hello}>{ModalTrigger}</ModalTriggerBackend>
    </>
  );
};

export const ModalContainer: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal container">{children}</div>;
};

export const ModalTrigger: FC<{ children: ReactNode }> = ({ children }) => {
  return <div key="modal trigger">{children}</div>;
};

const ModalContainerBackend: FC<{
  setHello: (value: { fn: () => void }) => void;
  children: ReactNode;
}> = ({ setHello, children }) => {
  return (
    <div
      className="bg-zinc-200 p-4"
      onClick={() => setHello({ fn: () => console.log("new") })}
    >
      {children}
    </div>
  );
};

const ModalTriggerBackend: FC<{
  hello: { fn: () => void };
  children: ReactNode;
}> = ({ hello, children }) => {
  return (
    <div onClick={hello.fn} className="border p-4">
      {children}
    </div>
  );
};

export default Modal;


Putting a function in an object fixed the issue, the container was logging "new" because with useState() you can make an expression for your new value useState((prev) => prev + 1), but I was using console.log("new") so it was running it, and set the new value to undefined.
Answer