轻松控制页面卡片隐藏显示

1,197 阅读2分钟

发现问题

  • 大量页面卡片,需要定义大量state。
  • 逻辑千丝万缕,最后导致显示隐藏失控。

解决问题

  • 可以批量关闭/开启和一键关闭所有页面卡片,丛容进行场景切换
  • 可以追加显示页面卡片(携带参数)
  • 可以关闭指定页面卡片
  • 可以记录历史并back

上代码

目录结构

image.png

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;

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 {
  //支持两种形式,第二种基本使用场景比较少
  defaultPaths?: 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}</>;
};

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);
      return findRoute && findRoute?.param;
    },
    [states],
  );

  return {
    isVisible,
    push,
    append,
    replace,
    back,
    useParam,
  };
};

export default useRouter;

index.tsx

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

demo

    // 都会被纳入状态管理
    export const Page =() => {
    
    
    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 就行页面的管理
        return ()
    }
  

说明: 部分功能没有实现,可以根据自己需求进行功能完善