我有一个要求,我需要在 nextjs 中创建一个包含选项卡组件的 Web 应用程序。
这个想法是,这将处理每个选项卡中的多个实体,例如,我有一个搜索栏来选择不同的产品,当我选择一个产品时,会使用该产品信息以及用户手动填写的表单创建一个新选项卡.
每次我选择新产品时,都会打开一个新选项卡,但我不应该丢失在第一个选项卡中输入的内容。
我需要能够在选项卡之间切换而不丢失状态。
我想知道有什么简单直接的方法吗?一个简单的例子就很好了。
我已经使用 zustand 实现了这一点,并将每个选项卡内容更改存储在一个变量中,然后在打开选项卡时获取它,但它看起来很脏并且不可维护。
可以使用 React 的状态管理和上下文 API 简化处理动态创建的选项卡及其在 Next.js 中的状态。
首先,创建一个上下文来管理选项卡的状态。
// contexts/TabsContext.js
import { createContext, useContext, useState } from 'react';
const TabsContext = createContext();
export const useTabs = () => useContext(TabsContext);
export const TabsProvider = ({ children }) => {
const [tabs, setTabs] = useState([]);
const [activeTab, setActiveTab] = useState(null);
const addTab = (tab) => {
setTabs([...tabs, tab]);
setActiveTab(tab.id);
};
const removeTab = (id) => {
setTabs(tabs.filter(tab => tab.id !== id));
if (activeTab === id) {
setActiveTab(tabs.length > 0 ? tabs[0].id : null);
}
};
const switchTab = (id) => {
setActiveTab(id);
};
return (
<TabsContext.Provider value={{ tabs, activeTab, addTab, removeTab, switchTab }}>
{children}
</TabsContext.Provider>
);
};
该组件将处理选项卡和每个选项卡内的表单的渲染。
// components/Tabs.js
import { useTabs } from '../contexts/TabsContext';
const Tabs = () => {
const { tabs, activeTab, addTab, removeTab, switchTab } = useTabs();
return (
<div>
<div className="tab-list">
{tabs.map(tab => (
<button key={tab.id} onClick={() => switchTab(tab.id)}>
{tab.title}
<span onClick={() => removeTab(tab.id)}>x</span>
</button>
))}
<button onClick={() => addTab({ id: Date.now(), title: 'New Tab', content: '' })}>
+ New Tab
</button>
</div>
<div className="tab-content">
{tabs.map(tab => (
tab.id === activeTab ? <div key={tab.id}>{tab.content}</div> : null
))}
</div>
</div>
);
};
export default Tabs;
每个选项卡都会包含一个需要保存数据的表单。
// components/TabForm.js
import { useState } from 'react';
import { useTabs } from '../contexts/TabsContext';
const TabForm = ({ tabId }) => {
const { tabs, setTabs } = useTabs();
const tab = tabs.find(tab => tab.id === tabId);
const [formData, setFormData] = useState(tab ? tab.content : '');
const handleChange = (e) => {
setFormData(e.target.value);
setTabs(tabs.map(tab => tab.id === tabId ? { ...tab, content: e.target.value } : tab));
};
return (
<form>
<textarea value={formData} onChange={handleChange} />
</form>
);
};
export default TabForm;
使用 TabsProvider 包装主应用程序组件,为所有组件提供上下文。
// pages/_app.js
import { TabsProvider } from '../contexts/TabsContext';
function MyApp({ Component, pageProps }) {
return (
<TabsProvider>
<Component {...pageProps} />
</TabsProvider>
);
}
export default MyApp;
最后,使用页面中的选项卡组件来查看它的实际效果。
// pages/index.js
import Tabs from '../components/Tabs';
export default function Home() {
return (
<div>
<h1>Dynamic Tabs Example</h1>
<Tabs />
</div>
);
}