0

I'm developing a React TypeScript application where I've implemented tabbed content, similar to a browser. Each tab contains a component, and I've encountered an issue where switching tabs causes the components to restart, leading to loss of data in forms, open modals, etc. These components are stored in a list of objects. How can I ensure that switching tabs doesn't cause the component to restart, thus preserving the data within it?


Here's what I've tried so far:

  • Initially, I stored the components directly in an array of objects and rendered them based on the active tab index.
  • I also experimented with React Router and conditional rendering, but couldn't prevent the component from reinitializing when switching tabs.
interface MainContentTab {
  id: string;
  title: string;
  content: JSX.Element;
  history: JSX.Element[];
  icon?: JSX.Element;
  state?: any;
}
...

export const useTabs = () => {
  return useContext(TabsContext);
};

export const TabsProvider = ({ children }: { children: ReactNode }) => {
  const [tabs, setTabs] = useState<MainContentTab[]>([]);
  const [activeTab, setActiveTab] = useState<string>("");
  ...
  return (
    <TabsContext.Provider value={{ tabs, addTab, ... }}> {children} </TabsContext.Provider>
  );
};
const MainContentTabs = () => {
  return (<>
    <Box
      component="main"
      className="MainContent"
      ... />
      {/* solution proposed from Alex Wayne, 
          it works but I really want to save the state, 
          maby for refreshing the site? */}
      {tabs.map((tab, index) => (
        <Box sx={{ display: (tab.id === activeTab) ? "block" : "none" }}>
          {tab.content || null} 
        </Box>
      ))}
        
      {/* Old solution */}
      {/* {tabs.find(tab => tab.id === activeTab)?.content || null} */}
    </Box> 

    {contextMenuPos && (
      <TabsContextMenu 
        tabId={contextMenuTabId} 
        x={contextMenuPos.x} 
        y={contextMenuPos.y} 
        onClose={handleCloseContextMenu} />
    )} 
  </>);
};

This image shows the old solution, but I want a more solution that saves the component render status: enter image description here

What I was expecting:

  • I expected the components to retain their state and not reinitialize when switching tabs, similar to how browsers preserve the state of opened tabs.
2
  • Where's the code where you render the selected tab? That's likely where the issue is. Commented Mar 8, 2024 at 23:19
  • I really forgot it, but now i edited my first post and add it in it Commented Mar 9, 2024 at 13:29

1 Answer 1

2

If a component is no longer being rendered, it will be destroyed. And if you then render it again, it will be recreated.

So you are rendering tabs like this:

{ selectedTab === 'a' && <MyTabA /> }
{ selectedTab === 'b' && <MyTabB /> }

Then when selectedTab becomes 'a', the <MyTabA /> component is created and rendered. When it becomes 'b', the component and all its state are destroyed.


So instead, you want to render all your tabs, but just hide them being displayed.

<div style={{ display: selectedTab === 'a' ? 'block' : 'none'><MyTabA /></div>
<div style={{ display: selectedTab === 'b' ? 'block' : 'none'><MyTabB /></div>

Now they all exist at the same time and are all rendered simultaneously, but you are only showing one at a time.

This way the components never get destroyed as you switch tabs.

Sign up to request clarification or add additional context in comments.

2 Comments

Is there any better way? I thought i could somehow save the state like React.useMemo (I tried, but it didn't worked). Thanks anyway, it will be my solution for now, but I will still search for another way.
If you want to preserve your state between page refreshes, that's sort of a different problem. You would have to persist your state data to somewhere outside of react like local storage or the the page URL. There's lot of solutions for that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.