我正在try 为React写标签,我不明白为什么只有在第二次点击它之后才将活动类应用于按钮

import { useState } from "react";

function buttonCreator() {
    const buttonStateChangers = [];
    return function SwitchTabButton({ loadTab, tabContent, tabName }) {
    console.log(`create ${tabName}`)
        const [state, toggleState] = useState("inactive");

        buttonStateChangers.push(toggleState);
        function handleClick() {
            if (state === "active") {
                return;
            }
            buttonStateChangers.forEach((changeState) => {
                changeState("inactive");
            });
            toggleState("active");
            loadTab(tabContent);
        }
        return (
            <button className={state} onClick={handleClick}>
                {tabName}
            </button>
        );
    };
}

export default function Tabs() {
  console.log("create tabs")
    const SwitchTabButton = buttonCreator();
  const [tab, loadTab] = useState(null);
    const tabsData = [
        {
            name: "Button 1",
            content: "Tab 1",
        },
        {
            name: "Button 2",
            content: "Tab 2",
        },
        {
            name: "Button 3",
            content: "Tab 3",
        },
    ];
    return (
        <>
            {tabsData.map((data, index) => {
                return (
                    <SwitchTabButton
                        key={index}
                        loadTab={loadTab}
                        tabName={data.name}
                        tabContent={data.content}
                    />
                );
            })}
            {tab}
        </>
    );
}

我注意到,当您单击一个按钮时,Tabs组件正在重建,因此按钮也在重建.我猜这是因为SwitchTabButton将loadTab作为参数,而loadTab函数与更改后的状态相关联.

推荐答案

您的Tabs组件正在动态创建SwitchTabComponentevery的渲染,这意味着您的状态实际上在重新渲染时丢失.您最好改用Reaction上下文API(或者甚至是Tab组件的更简单的回调),执行如下操作:

const TabContext = React.createContext({
  activeIndex: 0,
  changeIndex: (index) => {},
});

function Tab({ tabName, tabIndex }) {
  const { activeIndex, changeIndex } = useContext(TabContext);

  // you can now use this to determine whether or not the given Tab component should be in an active state
  const isActive = activeIndex === tabIndex;

  function handleClick() {
    changeIndex(tabIndex);
  }

  return <button className={isActive ? "active" : "inactive"}>{tabName}</button>
}

function Tabs() {
  const [activeIndex, setActiveIndex] = useState(0);
  const changeIndex = (index) => setActiveIndex(index);

  // ...your tabContents, etc.

  const tabContent = tabContents[activeIndex].content;

  return (
    <TabContext.Provider value={{ activeIndex, changeIndex }}>
      {
        tabContents.map((data, index) =>
          <Tab
            key={index}
            tabName={data.name}
            tabIndex={index} />
        )
      }
      {content}
    </TabContext.Provider>
  );
}

如果你需要访问嵌套组件树中其他地方的"active"标签,React上下文API在这里很有用;否则这个解决方案就太过分了,你可以简单地将activeIndexchangeIndex作为props传递给你的Tab组件.

Reactjs相关问答推荐

react 下拉菜单任务

在任何渲染之前在ReactJs中获取数据

如何将 npm 包添加到我的 Vite + React 应用程序中?

使用reactrouterdom时显示"对象无效作为React子组件"错误

CORS策略:对预检请求的响应未通过访问控制判断:没有Access-Control-Allow-Origin

未捕获的运行时错误:对象作为 React 子项无效

字段是必需的,当它没有定义时

为什么我的 Next.js (React) 组件只有在页面中时才有效?

如何初始化 redux 全局存储 preloadedState

React - 使用 React 显示错误和积极alert

如何处理页面加载时发生的 reactjs 错误?

将props 传递给 NextJS 布局组件

如何检索包含动态段的未解析路径?

不能在我的代码中使用 .给我一个警告!有人知道解决方案吗?

如何将值从下拉列表传递到 select 上的输入?响应式JS

react-markdown 不渲染 Markdown

用 scss 覆盖 MUI

组件焦点上的 MUI 更改栏 colored颜色

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

react / firebase 基地.如何在我的项目中保存更新的数据?