Found the problem

  • Lots of page cards, lots of states to define.
  • Logic leads to show hide out of control.

To solve the problem

  • You can batch close/open or one-click close all page cards to switch scenarios
  • Can append display page card (with parameters)
  • You can close the specified page card
  • Can record history and back

In the code

The directory structure

router-context.tsx

import React from 'react';
// router-context.tsx
export interface State<T = any> {
  path: string; visible? : boolean; param? : T; }export interface RouteContextValue {
  states: State[];
  setStates: (states: State[]) = > void;
}

export const RouteContext = React.createContext<RouteContextValue>(
  {} as RouteContextValue,
);

const RouteContextProvider: React.FC<RouteContextValue> = props= > {
  const{ children, ... rest } = props;return <RouteContext.Provider value={rest}>{children}</RouteContext.Provider>;
};

export const useRouteContext = (): RouteContextValue= >
  React.useContext<RouteContextValue>(RouteContext);

export default RouteContextProvider;

Copy the code

router.tsx

import React from 'react';
import RouteContextProvider, { State } from './router-context';
import useRouter from './use-router';

export interface RouteProps {
  path: string;
}

export interface RoutesProps {
  // Support two forms, the second basic use scenario is lessdefaultPaths? : string[]; defaultRoutes? : State[]; }export const Routes: React.FC<RoutesProps> = props= > {
  const { children, defaultPaths, defaultRoutes } = props;
  const [states, setStates] = React.useState<State[]>(() = > {
    if (defaultRoutes && defaultRoutes.length > 0) {
      return defaultRoutes;
    } else if (defaultPaths && defaultPaths.length > 0) {
      return defaultPaths.map(i= > ({ path: i, visible: true }));
    } else {
      return[]; }});return (
    <RouteContextProvider states={states} setStates={setStates}>
      {children}
    </RouteContextProvider>
  );
};

export const Route: React.FC<RouteProps> = props= > {
  const { children, path } = props;
  const { isVisible } = useRouter();
  const visible = isVisible(path);
  return <>{visible && children}</>;
};

Copy the code

use-router.ts

import React from 'react';
import { useRouteContext, State } from './router-context';

const useRouter = () = > {
  const { states, setStates } = useRouteContext();

  const isVisible = React.useCallback(
    (path: string) = > {
      return states.some(i= > i.path === path && i.visible);
    },
    [states],
  );

  const append = React.useCallback(
    (path: string, param: any = {}) = > {
      const nextStates = states.concat([
        {
          path,
          visible: true,
          param,
        },
      ]);
      setStates(nextStates);
    },
    [states],
  );

  const push = React.useCallback(
    (path: string, param: any = {}) = > {
      const nextStates = states
        .map(i= > ({
          ...i,
          visible: false,
        }))
        .concat([
          {
            path,
            visible: true,
            param,
          },
        ]);
      setStates(nextStates);
    },
    [states],
  );

  const replace = React.useCallback(
    (path: string, param: any = {}) = > {
      const length = states.length;
      const nextStates = states.map((i, idx) = > {
        return idx === length - 1
          ? {
              path,
              visible: true,
              param,
            }
          : i;
      });
      setStates(nextStates);
    },
    [states],
  );

  const back = React.useCallback(
    (param: any = {}) = > {
      const length = states.length;
      if (length > 0) {
        const nextStates = states.reduce((prev, c, idx) = > {
          if (length > 1 && idx === length - 2) { prev.push({ ... c, param,visible: true}); }else if(idx ! == length -1) {
            prev.push(c);
          }
          return prev;
        }, [] as State[]);
        setStates(nextStates);
      }
    },
    [states],
  );

  const useParam = React.useCallback(
    (path: string) = > {
      const findRoute = states.find(o= > o.path === path && o.visible);
      returnfindRoute && findRoute? .param; }, [states], );return {
    isVisible,
    push,
    append,
    replace,
    back,
    useParam,
  };
};

export default useRouter;
Copy the code

index.tsx

export { default as useRouter } from './use-router';
export { Routes, Route } from './router';

Copy the code

demo

    // will be included in state management
    export constPage = () => {return (
     <Routes defaultPaths={['landing']} >
      <Route path={'landing'} >
        <Landing />
      </Route>
      <Route path={'create-or-update'} >
        <CreateOrUpdate />
      </Route>
      <Route path={'list'} >
        <List />
      </Route>
    </Routes>)}const Page1 = () = > {
        const {push, append} = useRouter();
        // Push append to manage the page
        return()}Copy the code

Note: some functions are not realized, you can improve the function according to your own needs