React Tab组件className切换(active/inactive)实现方案求助
Let's break down what's going wrong and fix this tab state/className issue step by step:
The Core Problem
Your current setup is passing a state-updating function (instead of the actual active tab value) to the Tab component. When you try to compare active === tab, you're comparing a function to a string—this will never be true, which is why your tabs aren't updating their styles correctly. Also, scattered state across components leads to inconsistencies.
Step 1: Fix the Tabs Component
First, we'll clarify the props for Tabs—it should receive the current active tab value and a callback to update the tab, not mix the two into a single prop.
// Tabs.jsx import React from "react"; import PropTypes from "prop-types"; import Tab from "./Tab/Tab.jsx"; import "./styles.scss"; const Tabs = ({ tabs, activeTab, onTabChange }) => { const handleToggle = (tab) => { onTabChange(tab); console.log('selected tab from Tabs', tab); }; return ( <div className="tabs-container"> {tabs.map((tab) => ( <Tab key={tab} tab={tab} onToggle={handleToggle} activeTab={activeTab} // Pass the actual active tab value here /> ))} </div> ); }; // Add propTypes to catch type errors early Tabs.propTypes = { tabs: PropTypes.arrayOf(PropTypes.string).isRequired, activeTab: PropTypes.string.isRequired, onTabChange: PropTypes.func.isRequired, }; export default Tabs;
Step 2: Fix the Tab Component
Now, the Tab component will receive the actual active tab value, so we can correctly compare it to the tab's own value. We'll also use classnames to clean up the dynamic className logic.
// Tab.jsx import React from "react"; import classnames from 'classnames'; import { Button } from "core"; // Make sure to import your Button component! import "./styles.scss"; const Tab = ({ activeTab, onToggle, tab }) => { // Correct comparison: string vs string const isActive = activeTab === tab; return ( <div className="tab-container"> <Button as="button" format="textOnly" onClick={() => onToggle(tab)} // Use classnames for cleaner dynamic class assignment className={classnames( "tab-button", // Base class for all tabs { "tab-button-active": isActive, "tab-button-inactive": !isActive } )} > {tab} </Button> </div> ); }; export default Tab;
Step 3: Manage State in a Parent Component
State should live in the highest component that needs access to it (like your app's root or a component that renders both Tabs and GlobalNav). This ensures consistency across components.
// Example parent component (e.g., App.js) import React, { useState } from "react"; import Tabs from "./Tabs/Tabs"; import GlobalNav from "./GlobalNav"; const App = () => { // Initialize with your default active tab const [activeTab, setActiveTab] = useState("Your Default Tab"); const handleTabChange = (newTab) => { setActiveTab(newTab); // Sync this state with GlobalNav if needed }; // Your list of tabs const tabsList = ["Tab 1", "Tab 2"]; return ( <div> <Tabs tabs={tabsList} activeTab={activeTab} onTabChange={handleTabChange} /> <GlobalNav selectedTab={activeTab} /> </div> ); }; export default App;
Key Takeaways
- Centralize state: Keep tab state in one parent component instead of scattering it across
TabsandTab—this avoids inconsistencies. - Pass values, not functions: Make sure
Tabreceives the actual active tab string for comparison, not the state-updating function. - Use classnames: It makes dynamic className logic more readable and maintainable than raw ternary operators.
内容的提问来源于stack exchange,提问作者Christian

