我想在Reaction中开发一个Tabs组件.当我试图关闭一个元素并将活动状态分配给上一个或下一个选项卡时,我的setFiles方法正确地更新了文件数组,但是当重新加载上下文时,派生状态openedFiles没有使用正确的文件状态.

这是我的代码:

context-provider.tsx

const IdeEmulatorContextProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
  const [files, setFiles] = useState<IdeFile[]>([]);
  const openedFiles = files.filter((element: IdeFile) => element.opened);
  
  const selectFileHandler = (event: any) => {
    // ...
  };

  const openFileInTab = (file: IdeFile) => {
    // ...
  };

  const closeTab = (name: string) => {
    setFiles((currentFiles: IdeFile[]) => {
      let indexToUpdate: number;

      const newFiles = currentFiles.map((element, index) => {
        if (name === element.name) {
          indexToUpdate = index;
          return {
            ...element,
            opened: false,
            active: false
          };
        } else {
          return element;
        }
      });

      if (indexToUpdate! >= 1) {
        newFiles[indexToUpdate!-1] = {
          ...newFiles[indexToUpdate!-1],
          active: true
        };
      } else {
        if (openedFiles.length > 1) {
          newFiles[indexToUpdate!+1] = {
            ...newFiles[indexToUpdate!+1],
            active: true
          };
        }
      }

      return [...newFiles];
    });
  };

  const selectTab = (tabIndex: number) => {
    setFiles((currentFiles: IdeFile[]) => {
      const newFiles = currentFiles.map((element, index) => {
        if (tabIndex === index) {
          return {
            ...element,
            active: true
          };
        } else {
          return {
            ...element,
            active: false
          };
        }
      });

      return [...newFiles];
    });
  };

  const ctxValue = {
    files,
    openedFiles,
    selectFileHandler,
    openFileInTab,
    closeTab,
    selectTab
  };

  return <IdeEmulatorContext.Provider value={ctxValue}>
    {children}
  </IdeEmulatorContext.Provider>
};

tabs-list.tsx

const TabsList = () => {
  const ctx = useContext(IdeEmulatorContext);

  const closeHandler = (name: string) => {
    ctx.closeTab(name)
  }

  return <nav className="nav-bar">
    <ol className="tabs">
      {ctx.openedFiles.map((element: IdeFile, index: number) => <li key={element.name} className={element.active ? 'active' : ''} onClick={() => ctx.selectTab(index)}>
        {element.name} {element.active ? <button className="btn-close" onClick={() => closeHandler(element.name)}>x</button> : null}
      </li>)}
    </ol>
  </nav>
};

提前谢谢你了!

推荐答案

你面临的问题是因为close click event人中的bubbling人.让我来分析一下正在发生的事情:

  • 单击更新状态的tab element,并将active标志设置为TRUE
  • 现在,您可以通过单击X按钮来close元素.此操作触发元素的两个函数:closeHandlerctx.selectTab.对ctx.selectTab的触发是由按钮上的click传播到父按钮(称为event bubbling)引起的.

为了防止这种情况,你需要停止event propagation.以下是实现这一点的方法:

const closeHandler = (event: React.MouseEvent<HTMLElement>, name: string) => {
     event.stopPropagation();
     ctx.closeTab(name);
}

//....
onClick={(e) => closeHandler(e, element.name)}

Edit (Just an advice, not much related with the actual issue) :我注意到您的逻辑中的另一个问题是,您传递的是ctx.selectTab(index)中的index作为标识符.每当openedFiles中的项被更改时,这将给您带来不想要的错误.要防止出现这种情况,请使用实际上是唯一的内容,例如nametabId.

希望这能有所帮助:)

Reactjs相关问答推荐

如何在useEffect中使用useParams()

从`redux—thunk`导入thunk `在stackblitz中不起作用

如何创建react router v6的自定义子路由?

Redux Store未触发React组件中的重新呈现

MUI:在props 主题中找到的值:;错误;是[Object],而不是字符串或数字

React组件未出现

使用Next.js和Next-intl重写区域设置

根据用户 Select 的注册类型更改表单字段

如何在中间件中获取 nextAuth 会话

React设置上下文并进行导航

如何在 React.js 中提取 PDF 的内容?

React - 添加了输入数据但不显示

使用 axios 响应路由 Dom 操作

意外的标记.您可能需要一个合适的加载器来处理这种文件类型.书?.img? /*#__PURE__*/React.createElement("img",

页面加载时不显示数组中的数据

响应式媒体 React Tailwind

Cypress - 在继续之前等待下一个按钮重新出现

为什么我在运行一些 npm react 命令时会收到这些警告?

RTK 查询 POST 方法不会改变数据

点击提交后自动添加#