React Accordion组件中onToggle函数报“not a function”错误求助
CbdsAccordion组件onToggle "not a function" 错误排查与修复
开发CbdsAccordion组件时遇到问题:调用onToggle函数时持续触发“not a function”错误,尝试在props、默认props及map循环中定义onToggle,要么报错要么提示未使用。原代码如下:
import { useState } from "react"; import PropTypes from "prop-types"; import './CbdsAccordion.scss'; const CbdsAccordion = ({ items, multiple = false }) => { const [active, setActive] = useState(0); const [visibility, setVisibility] = useState(false); const isActive = () => (multiple ? visibility : active); const toggleVisibility = ({onToggle}) => { setVisibility((visible) => !visible); onToggle(); }; return ( <div className='cbds-c-accordion'> {items.map((item, index) => ( <div className={`card ${isActive() ? "accordion-active" : ""}`} key={index} active={active === index} multiple={multiple} onToggle={() => setActive((active => active === index ? '' : index))} > <div className='card-header' onClick={toggleVisibility}> {item.accordionLabel} <span className='accordion-icon'>+</span> </div> <div className='card-body'> {item.accordionPanel} </div> </div> ) )} </div> ) } CbdsAccordion.propTypes = { multiple: PropTypes.bool, active: PropTypes.bool }; CbdsAccordion.defaultProps = { multiple: false, active: false }; export default CbdsAccordion
错误原因分析
- toggleVisibility参数错误:该函数尝试解构
onToggle参数,但点击事件触发时未传递任何参数,导致onToggle为undefined,调用时触发"not a function"错误。 - 无效的props传递:将
onToggle作为原生div的props无意义,div不会处理该属性,也无法传递到点击事件中。 - 状态逻辑混乱:
- 多选模式用单个布尔值
visibility控制所有项的展开/收起,不符合多选需求; isActive函数返回值类型不统一(多选返回布尔,单选返回数字),导致类名判断逻辑错误。
- 多选模式用单个布尔值
- props定义缺失:组件未将
onToggle作为可接收的props,父组件无法传入回调,自定义的onToggle也未正确关联。
修复方案及完整代码
import { useState } from "react"; import PropTypes from "prop-types"; import './CbdsAccordion.scss'; const CbdsAccordion = ({ items, multiple = false, onToggle // 新增:接收父组件传入的回调 }) => { // 调整状态:多选用数组存活跃索引,单选存单个索引 const [activeIndexes, setActiveIndexes] = useState(multiple ? [] : 0); // 修正isActive:判断当前索引是否处于活跃状态 const isActive = (index) => { if (multiple) { return activeIndexes.includes(index); } return activeIndexes === index; }; // 重构toggle函数:接收当前索引,处理不同模式的状态切换 const toggleVisibility = (index) => { let newActive; if (multiple) { // 多选模式:切换当前索引的活跃状态 newActive = activeIndexes.includes(index) ? activeIndexes.filter(i => i !== index) : [...activeIndexes, index]; } else { // 单选模式:切换当前索引,或取消(如果已经是活跃状态) newActive = activeIndexes === index ? null : index; } setActiveIndexes(newActive); // 调用外部传入的onToggle(如果存在) if (typeof onToggle === 'function') { onToggle(index, newActive); } }; return ( <div className='cbds-c-accordion'> {items.map((item, index) => ( <div className={`card ${isActive(index) ? "accordion-active" : ""}`} key={index} > <div className='card-header' onClick={() => toggleVisibility(index)}> {item.accordionLabel} <span className='accordion-icon'>{isActive(index) ? "-" : "+"}</span> </div> {isActive(index) && ( // 仅当活跃时渲染内容 <div className='card-body'> {item.accordionPanel} </div> )} </div> ))} </div> ) } CbdsAccordion.propTypes = { multiple: PropTypes.bool, items: PropTypes.arrayOf(PropTypes.shape({ accordionLabel: PropTypes.node.isRequired, accordionPanel: PropTypes.node.isRequired })).isRequired, onToggle: PropTypes.func // 新增:定义onToggle的prop类型 }; CbdsAccordion.defaultProps = { multiple: false }; export default CbdsAccordion
关键修改点
- 状态优化:根据
multiple模式选择合适的状态类型(数组/单个值),实现正确的多选/单选逻辑。 - 修正点击事件:点击时传递当前项的索引给
toggleVisibility,不再依赖无效的props传递。 - onToggle处理:将
onToggle作为组件props接收,仅在它是函数时才调用,避免报错。 - 渲染逻辑优化:仅当项处于活跃状态时渲染
card-body,同时更新图标显示(+/-切换)。 - props类型完善:补充
items的必填类型定义,明确onToggle的函数类型。
内容的提问来源于stack exchange,提问作者RB50
相关产品推荐
相关产品推荐

