Uncaught TypeError: isOpen is not a function

huangapple go评论74阅读模式
英文:

Uncaught TypeError: isOpen is not a function

问题

我试图将我的基于类的组件转换为基于函数的组件,这是我在学习REACT时写的一段时间,但在转换过程中,出现了一个错误,提示isOpen不是一个函数,我有点不明白,因为我将其定义为状态并在handleToggle()中调用它,然后在组件的logo处调用它。

import React, { useState, useEffect } from "react";
import logo from "../images/logo.svg";
import { FaAlignRight } from "react-icons/fa";
import { Link } from "react-router-dom";
import Badge from '@mui/material/Badge';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';

export default function Navbar(){

  const [anchorEl, setAnchorEl] = useState(null);
  const open = Boolean(anchorEl);
  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };
  const handleClose = () => {
    setAnchorEl(null);
  };

  const [isOpen, setIsOpen] = useState(false); // 改为false

  useEffect(() => {
    handleToggle();
  });

  const handleToggle = () => {
    setIsOpen(!isOpen); // 改为这种方式
  };

  return (
    <nav className="navbar">
      <div className="nav-center">
        <div className="nav-header">
          <Link to="/">
            <img src={logo} alt="Beach Resort" />
          </Link>
          <button
            type="button"
            className="nav-btn"
            onClick={handleToggle}
          >
            <FaAlignRight className="nav-icon" />
          </button>
        </div>
        <ul
          className={isOpen ? "nav-links show-nav" : "nav-links"}
        >
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/rooms">Rooms</Link>
          </li>
        </ul>
        <Badge badgeContent={4} color="primary" 
            id="basic-button"
            aria-controls={open ? 'basic-menu' : undefined}
            aria-haspopup="true"
            aria-expanded={open ? 'true' : undefined}
            onClick={handleClick}
        >
          <i className="fa-solid fa-cart-shopping text-light"
            style={{ fontSize: 25, cursor: "pointer" }}
          ></i>
        </Badge>
      </div>
      <Menu
        id="basic-menu"
        anchorEl={anchorEl}
        open={open}
        onClose={handleClose}
        MenuListProps={{
          'aria-labelledby': 'basic-button',
        }}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </nav>
  );
}

主要的更改是将isOpen的初始状态设置为false,然后在handleToggle函数中更新它的状态,而不是尝试将它当作函数来调用。这应该解决你遇到的问题。

英文:

I was trying to convert my class-based component to function based component, which I wrote some while when I was learning REACT, while converting this, I got an error that isOpen is not the function which I kinda dint get as I defined it as a state and called in handleToggle(), which is then being called at the logo of my component.

import React, { useState, useEffect } from &quot;react&quot;;
import logo from &quot;../images/logo.svg&quot;;
import { FaAlignRight } from &quot;react-icons/fa&quot;;
import { Link } from &quot;react-router-dom&quot;;
import Badge from &#39;@mui/material/Badge&#39;;
import Menu from &#39;@mui/material/Menu&#39;;
import MenuItem from &#39;@mui/material/MenuItem&#39;;
export default function Navbar(){
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) =&gt; {
setAnchorEl(event.currentTarget);
};
const handleClose = () =&gt; {
setAnchorEl(null);
};
const [isOpen, setIsOpen] = useState(null);
useEffect(() =&gt;{
handleToggle();
});
// state = {
//   isOpen: false,
// };
const handleToggle = () =&gt; {
setIsOpen(isOpen() );
};
return (
&lt;nav className=&quot;navbar&quot;&gt;
&lt;div className=&quot;nav-center&quot;&gt;
&lt;div className=&quot;nav-header&quot;&gt;
&lt;Link to=&quot;/&quot;&gt;
&lt;img src={logo} alt=&quot;Beach Resort&quot; /&gt;
&lt;/Link&gt;
&lt;button
type=&quot;button&quot;
className=&quot;nav-btn&quot;
onClick={handleToggle}
&gt;
&lt;FaAlignRight className=&quot;nav-icon&quot; /&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;ul
className={isOpen ? &quot;nav-links show-nav&quot; : &quot;nav-links&quot;}
&gt;
&lt;li&gt;
&lt;Link to=&quot;/&quot;&gt;Home&lt;/Link&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;Link to=&quot;/rooms&quot;&gt;Rooms&lt;/Link&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;Badge badgeContent={4} color=&quot;primary&quot; 
id=&quot;basic-button&quot;
aria-controls={open ? &#39;basic-menu&#39; : undefined}
aria-haspopup=&quot;true&quot;
aria-expanded={open ? &#39;true&#39; : undefined}
onClick={handleClick}
&gt;
&lt;i className=&quot;fa-solid fa-cart-shopping text-light&quot;
style={{ fontSize: 25, cursor: &quot;pointer&quot; }}
&gt;&lt;/i&gt;
&lt;/Badge&gt;
&lt;/div&gt;
&lt;Menu
id=&quot;basic-menu&quot;
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
&#39;aria-labelledby&#39;: &#39;basic-button&#39;,
}}
&gt;
&lt;MenuItem onClick={handleClose}&gt;Profile&lt;/MenuItem&gt;
&lt;MenuItem onClick={handleClose}&gt;My account&lt;/MenuItem&gt;
&lt;MenuItem onClick={handleClose}&gt;Logout&lt;/MenuItem&gt;
&lt;/Menu&gt;
&lt;/nav&gt;
);
}

EVERY PIECE OF ADVICE WILL BE APPRECIATED

答案1

得分: 1

isOpen 是一个数值,不是一个函数。尝试使用 setIsOpen(p => !p)

英文:

isOpen is a value, not a function. Try setIsOpen(p =&gt; !p)

答案2

得分: 1

useState 返回一个包含两个部分的数组:存储在状态中的值和用于更新它的函数。如果你调用 const [isOpen, setIsOpen] = useState(null)isOpen 是你的值(最初设置为 null),而 setIsOpen 是用于更新它的函数。

当你写 const handleToggle = () =&gt; { setIsOpen(isOpen()) } 时,你试图调用一个 null 值,这是不可能的,因为它不是一个函数。这就是错误消息告诉你的内容。

如果你想要切换 isOpen 的值,你应该将 isOpen 声明为布尔值,然后使用 setIsOpen 传入 isOpen 的相反值:

const [isOpen, setIsOpen] = useState(false);  // <= 最初将其设置为false

const handleToggle = () =&gt; {
  setIsOpen(!isOpen); // <= 当它为false时,将其设置为true,当它为true时将其设置为false
};

然而,如果你在没有依赖数组的情况下在 useEffect 中调用 handleToggle,就像你目前正在做的那样,它将在每次重新渲染时都被调用,这可能不是你想要的。你很可能希望在响应用户交互时调用它,比如响应HTML元素事件(如 onClick)。否则,你应该重构你的代码,以向 useEffect 添加必要的依赖项。

英文:

useState returns an array with two things: a value that is stored in state, and a function to update it. If you call const [isOpen, setIsOpen] = useState(null), isOpen is your value (originally set as null) and setIsOpen is a function to update it.

When you write const handleToggle = () =&gt; { setIsOpen(isOpen() ) }, you're trying to call a null value, which is impossible because it's not a function. That's what the error message is telling you.

Given you want to toggle the value for isOpen, what you should do instead is declare isOpen as a boolean, and call setIsOpen with the opposite of isOpen:

const [isOpen, setIsOpen] = useState(false);  // &lt;= set this originally to false

const handleToggle = () =&gt; {
  setIsOpen(!isOpen); // &lt;= this will set isOpen as true when it is false, and false when it is true
};

However, if you call handleToggle inside a useEffect with no dependency array, like you're doing, it will be called every time there is a rerender, which is probably not what you want. You most likely want to call this in response to a user interaction - so in response to an HTML element event (like onClick). Otherwise you should refactor your code to add the necessary dependencies to useEffect.

huangapple
  • 本文由 发表于 2023年2月18日 02:04:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487818.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定