react stateful tabs

Preserve the internal state of a component when it’s hidden.

2
0
TypeScript
React Stateful Tabs

Preserve the internal state of a component when it’s hidden

MIT License Coverage Code Style: Prettier

Overview

This component helps to preserve the internal state of a tab (or page) when it’s hidden, removing the need to hoist state to the parent or a central store to save it while switching tabs.

Usage

Simple Usage

const tabs = {
  GENERAL: ({ visible }) => (visible ? <h1>General Tab</h1> : null),
  ACTIVITIES: ({ visible }) => (visible ? <h1>Activites Tab</h1> : null)
};

function SomeComponent() {
  const [currentTab, setCurrentTab] = React.useState("GENERAL");

  return (
    <StatefulTabs>
      {() => (
        <div>
          <button onClick={() => setCurrentTab("GENERAL")}>General</button>
          <button onClick={() => setCurrentTab("ACTIVITIES")}>
            Activities
          </button>
          <StatefulTabs.Controller
            id={currentTab}
            render={tabProps => React.createElement(tabs[currentTab], tabProps)}
          />
          <StatefulTabs.View />
        </div>
      )}
    </StatefulTabs>
  );
}

<StatefulTabs.Controller>

id prop: string | number indicates the currently selected tab. Whenever it changes, it will create a new tab (if that id has not yet been opened), or show the existing instance with that id.
render prop: (tabProps: {visible: boolean, properties: Object, destroy: () => void, update: (newProperties: Object) => void}) => React.Element function that returns the component associated with the currently selected id

<StatefulTabs.View />

Placed anywhere within <StatefulTabs> to render the currently selected tab.

Usage With React Router

To derive the tab id from the current route URL, you can wrap StatefulTabs.Controller with the below component:

const ReactRouterTabController = ({ render, properties }) => routerProps => (
  <StatefulTabs.Controller
    id={routerProps.match.url}
    render={() => render(routerProps)}
  />
);

And then render it in a React Router Route:

<Router>
    <Route
      path="/:projectId"
      render={ReactRouterTabController({
        render: routerProps => <ProjectView projectId={routerProps.match.params.projectId} />
      })}
    />
</Router>

Usage With Reach Router

To derive the tab id from the current route URL, you can wrap StatefulTabs.Controller with the below component:

const ReachRouterTabController = ({ render, properties, ...routerProps }) => (
  <StatefulTabs.Controller
    id={routerProps.uri}
    properties={properties}
    render={React.useCallback((tabProps) => render({ ...tabProps, ...routerProps }), [render, routerProps])}
  />
);

And then render it inside of a Reach Router Router:

<Router>
  <ReachRouterTabController
    path="/:projectId"
    render={routerProps => (
      <ProjectView projectId={routerProps.projectId} />
    )}
  />
</Router>