У меня есть требование: мне нужно создать веб-приложение в nextjs, в котором есть компоненты вкладок.
Идея состоит в том, что это будет обрабатывать несколько объектов на каждой вкладке, например, у меня есть панель поиска для выбора разных продуктов, когда я выбираю один, создается новая вкладка с информацией об этом продукте, а также с формами, которые пользователь будет заполнять вручную.
Каждый раз, когда я выбираю новый продукт, открывается новая вкладка, но я не должен потерять то, что ввел на первой вкладке.
Мне нужно иметь возможность переключаться между вкладками без потери состояния.
Я хочу знать, есть ли какой-нибудь простой и прямой путь? простой пример будет отличным.
Я добился этого с помощью zustand и сохраняю изменения содержимого каждой вкладки в переменной, а затем извлекаю ее при каждом открытии вкладки, но она выглядит грязной и непригодной для обслуживания.
Обработку динамически создаваемых вкладок и их состояния в Next.js можно упростить с помощью API управления состоянием и контекста React.
Сначала создайте контекст для управления состоянием вкладок.
// 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 handleChangeEvent = (e) => {
setFormData(e.target.value);
setTabs(tabs.map(tab => tab.id === tabId ? { ...tab, content: e.target.value } : tab));
};
return (
<form>
<textarea value = {formData} onChange = {handleChangeEvent} />
</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>
);
}
@ahmedghanemkrid Используйте useRef для хранения содержимого каждой вкладки, предотвращая повторную визуализацию при переключении между вкладками.
как это именно работает?
Большое спасибо за ваше время и ответ, так что по сути здесь вы использовали контекст реагирования вместо внешней библиотеки управления состоянием. Но у меня есть еще один вопрос: можно ли как-то не использовать библиотеку управления состоянием и предотвратить повторную отрисовку существующих вкладок при переключении между вкладками? в этом случае мы сохраняем контент и не проводим повторную визуализацию, если вкладка переключается или добавляется, возможно? я все еще новичок, извините, если мой вопрос покажется глупым