You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中array.findIndex报“不是函数”错误及onClick自动触发状态更新问题排查

React状态管理与事件绑定问题排查与修复

我来帮你一步步解决这两个问题,顺便纠正一个React状态管理的核心误区:

问题1:findIndex is not a function 报错

你最开始用state.findIndex报错,原因很直接:你的全局state是一个对象(包含ids数组属性),而findIndex是数组专属方法,对象本身没有这个方法。所以必须先访问到数组state.ids,再调用findIndex——你改成state.ids.findIndex的操作完全正确,这个问题就是对变量类型的小误解导致的~

问题2:点击事件提前触发,所有active被设为true

你现在的onClick={changeActiveField(i.id)}写法,会在组件渲染的时候就立刻执行函数,而不是等用户点击时才触发。因为JSX里的onClick需要接收一个函数引用,你现在直接调用函数,相当于把函数执行的结果(undefined)传给了onClick,自然会提前执行。

修复方法很简单,用箭头函数包裹起来,让它变成一个点击时才会执行的回调:

onClick={() => changeActiveField(i.id)}

隐藏的核心问题:全局state无法触发组件重渲染

你现在用的是全局var state,但React组件的状态更新必须依赖自身的this.state和setState方法——直接修改全局变量不会触发组件重新渲染,所以哪怕你改了active的值,页面也不会同步更新。这才是你点击后看不到预期效果的关键!

完整修复方案

把全局state移到组件的state里,并用setState来规范更新状态:

  1. 重构组件的state初始化:
constructor(props) {
  super(props);
  // 把全局的ids移到组件自身的state中
  this.state = {
    ids: [
      { id: "iCBvfW08jlo", active: true },
      { id: "qvOcCQXZVg0", active: false },
      { id: "YXNC3GKmjgk", active: false },
    ]
  };
  // 绑定函数上下文(也可以用箭头函数定义组件方法替代)
  this.changeActiveField = this.changeActiveField.bind(this);
}
  1. 修改changeActiveField函数,用setState更新状态(注意不要直接修改原state,要创建新数组保证不可变性):
changeActiveField(targetId) {
  this.setState(prevState => {
    // 复制原数组,避免直接修改state
    const newIds = [...prevState.ids];
    // 找到之前active为true的项并设为false
    const activeIndex = newIds.findIndex(obj => obj.active === true);
    if (activeIndex !== -1) {
      newIds[activeIndex] = {...newIds[activeIndex], active: false};
    }
    // 找到点击的项并设为true
    const targetIndex = newIds.findIndex(obj => obj.id === targetId);
    if (targetIndex !== -1) {
      newIds[targetIndex] = {...newIds[targetIndex], active: true};
    }
    return { ids: newIds };
  });
}
  1. 修改渲染部分的代码,全部使用组件自身的this.state:
  • 优化firstActiveId函数:
function firstActiveId(ids) {
  const activeItem = ids.find(obj => obj.active);
  return activeItem ? activeItem.id : '';
}
  • 替换全局state为this.state,并给列表项添加唯一key:
<Embed
  active
  autoplay={false}
  color="white"
  hd={false}
  id={firstActiveId(this.state.ids)}
  iframe={{ allowFullScreen: true, style: { padding: 10 } }}
  placeholder={`http://img.youtube.com/vi/${firstActiveId(this.state.ids)}/hqdefault.jpg`}
  source="youtube"
/>

<div className="thumbs">
  {this.state.ids.map((item) => (
    <React.Fragment key={item.id}> {/* 必须加key,避免React渲染警告 */}
      <Image
        className="carouselitem"
        rounded fluid
        onClick={() => this.changeActiveField(item.id)}
        src={`http://img.youtube.com/vi/${item.id}/hqdefault.jpg`}
        size="small"
      />
      <h2>
        {item.id} {item.active ? "true" : "false"}
      </h2>
    </React.Fragment>
  ))}
</div>
  1. 最后移除原来的全局var state,现在组件完全用自身的state管理状态。

这样修改后,不仅解决了报错和事件提前触发的问题,还能保证状态更新后组件会自动重新渲染,点击缩略图就能正常切换active状态和对应的视频了~

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:12:41