You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React实现组件可见性切换时触发TypeError: visible.map is not a function错误求助

嘿,我一眼就看出问题所在啦!你遇到的 TypeError: visible.map is not a function 错误,核心原因是你把原本是数组类型的 state visible 改成了布尔值,导致后续调用 visible.map() 失败——毕竟布尔值可没有 map 方法。

问题出在哪?

  1. 你的 state 初始化是数组:const [visible, setVisible] = useState([...]),但点击按钮时写了 setVisible(visible => !visible)。这里的 visible 是当前的数组状态(数组属于真值),!visible 会直接把它转换成布尔值 false,state 类型就从数组变成了布尔值。
  2. 你传给子组件的 setVisible 也有同样问题:子组件里调用 props.setVisible(false) 或者 props.setVisible(visible => !visible),同样会把数组 state 改成布尔值,彻底破坏了后续渲染的基础。

修复方案:保持 state 为数组,只修改对应项的可见性

我们要做的是始终让 state 保持数组结构,点击按钮时只切换对应项的 visible 属性,而不是替换整个数组。

第一步:修正父组件代码

import { useState } from 'react';
import ExampleOne from './Examples/exampleOne.js';
import ExampleTwo from './Examples/exampleTwo.js';
import ExampleThree from './Examples/exampleThree.js';

function SectionTwo() {
  // 重命名state为items,更清晰表达它是多个项的集合
  const [items, setItems] = useState([
    { number: 1, Component: ExampleOne, visible: false },
    { number: 2, Component: ExampleTwo, visible: false },
    { number: 3, Component: ExampleThree, visible: false }
  ]);

  // 通用切换方法:只修改对应number项的visible状态
  const toggleItemVisibility = (itemNumber) => {
    setItems(prevItems => 
      prevItems.map(item => 
        item.number === itemNumber 
          ? {...item, visible: !item.visible} 
          : item
      )
    );
  };

  // 专门的关闭方法:给子组件用来点击外部关闭自身
  const closeItem = (itemNumber) => {
    setItems(prevItems => 
      prevItems.map(item => 
        item.number === itemNumber 
          ? {...item, visible: false} 
          : item
      )
    );
  };

  return (
    <div className="section-content seciton2">
      <p>We're no strangers to love<br/> You know the rules and so do I<br/> A full commitment's what I'm thinking of<br/> You wouldn't get this from any other guy<br/> I just wanna tell you how I'm feeling<br/> Gotta make you understand</p>
      <ul className="examples">
        {items.map((item) => (
          <li key={item.number}>
            <button 
              className={`example${item.number}`} 
              onClick={() => toggleItemVisibility(item.number)}
            >
              切换示例 {item.number}
            </button>
            {/* 只有当visible为true时,才渲染对应的子组件 */}
            {item.visible && (
              <item.Component 
                close={() => closeItem(item.number)}
              />
            )}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default SectionTwo;

第二步:修正子组件代码(以ExampleThree为例)

import { useEffect, useRef } from 'react';

function ExampleThree(props) {
  const exampleRef = useRef();

  useEffect(() => {
    const handler = (event) => {
      if (!exampleRef.current.contains(event.target)) {
        props.close();
      }
    };
    document.addEventListener("mousedown", handler);
    // 添加依赖项props.close,符合React Hooks规则
    return () => document.removeEventListener("mousedown", handler);
  }, [props.close]);

  return (
    <div className="example3-content" ref={exampleRef}>
      <p>We're no strangers to love<br/> You know the rules and so do I<br/> A full commitment's what I'm thinking of<br/> You wouldn't get this from any other guy<br/> I just wanna tell you how I'm feeling<br/> Gotta make you understand</p>
      <button onClick={props.close}>ha det</button>
    </div>
  );
}

export default ExampleThree;

关键修改点总结

  1. 保持state类型一致:始终让state是数组,只修改数组内对应项的属性,绝不把整个数组替换成布尔值。
  2. 拆分职责:父组件负责管理整体state,给子组件传递明确的close方法,避免子组件直接操作父组件的完整state,降低耦合度。
  3. 优化渲染逻辑:只在对应项visible为true时渲染子组件,减少不必要的渲染开销。

内容的提问来源于stack exchange,提问作者Sylvio

火山引擎 最新活动