react项目中封装一个通用的边界Boundary

37 篇文章 1 订阅
7 篇文章 0 订阅

# Boundary 

通用的边界,同时是一个Suspense 和一个 ErrorBoundary

正常情况不直接用,使用一下几个封装好的:

-Boundary.FullSizeLoading: 占满父容器全部高度,居中显示等待动画;

-Boundary.Loading: 占满一行,显示一个普通尺寸的等待动画;

-Boundary.Blank: 什么都不显示,加速速度足够快的话可以使用;

先看一下代码目录结构:

(1)index.tsx 

import {ComponentProps} from 'react';
import {Boundary as SuspenseBoundary,SuspenseBoundaryProps} from 'react-suspense-boundary';
import styled from '@emotion/styled';
import {times} from 'ramda';
import {Spin,Skeletion} from 'antd';
import {flexCenter} from './css/flex';
import fullSizeCenter from './FullSizeCenter/index';
import {defaultRenderError,defaultRenderFullSizeError} from './defaults';

interface Props extends SuspenseBoundaryProps{
    /**
     * 显示错误时是否占满整个容器
     */
    fullSize?:boolean;
}

function Boundary({fullSize =false,...props}:Props){
    return (
        <SuspenseBoundary 
           {...props}
           renderError={props.renderError ?? (fullSize ? defaultRenderFullSizeError : defaultRenderError)}
        />
    )
}

Boundary.FullSizeLoading = function FullSizeLoadingBoundary(props:SuspenseBoundaryProps){
    return (
        <Boundary 
            fullSize
            pendingFallback={
                <fullSizeCenter>
                    <Spin size="large" />
                </fullSizeCenter>
            }
        />
    )
}

export interface SkeletionProps extends SuspenseBoundaryProps,Omit<Components<typeof Skeletion>,'children'>{
    repeat?:number;
}

Boundary.Skeletion = function SkeletionBoundary({repeat=1,...props}:SkeletionProps){
    return (
        <Boundary 
            pendingFallback={
               <div>
                  {times(i => <Skeletion loading active key={i} {...props} />,repeat)}
               </div>
            }
            {...props}
        />
    )
}

Boundary.FullSizeSkeletion = function FullSizeSkeletionBoundary({repeat=1,...props}:SkeletionProps){
    return (
        <Boundary 
            fullSize
            pendingFallback={
                <fullSizeCenter>
                  {times(i => <Skeletion loading active key={i} {...props} />,repeat)}
                </fullSizeCenter>
            }
            {...props}
        />
    )
}

const LoadingContainer =styled.div`
    ${flexCenter};
    margin : 20px 0;
`

Boundary.Loading = function LoadingBoundary(props:SuspenseBoundaryProps){
    return(
        <Boundary 
          pendingFallback={
              <LoadingContainer>
                  <Spin />
              </LoadingContainer>
          }
          {...props}
        />
    )
}

Boundary.InlineLoading = function InlineLoadingBoundary(props:SuspenseBoundaryProps){
    return <Boundary pendingFallback={<Spin size="small" />} {...props} /> 
}

Boundary.Blank = function BlankBoundary(props:SuspenseBoundaryProps){
    return <Boundary pendingFallback={<fullSizeCenter />} {...props} /> 
}

export default Boundary;

 (2)defaults.tsx

inport Error from './Error';
import FullSizeCenter from './FullSizeCenter';

const renderErrorWithFullSize=(fullSize:boolean)=>(error:any)=>{
    const message = error?.message;
    const errorType=error?.responseStatus || '400';
    if(fullSize){
        return (
            <FullSizeCenter>
                <Error type={errorType} message={message} displayInDetail></Error>
            </FullSizeCenter>
        )
    } 
    return   <Error type={errorType} message={message} displayInDetail></Error>
}

export const defaultRenderError = renderErrorWithFullSize(false);
export const defaultRenderFullSizeError = renderErrorWithFullSize(true);

(3)Error/index.tsx

import {createElement} from 'react';
import {useToggle} from '@huse/boolean';
import {Empty,Gap,Button} from 'antd';
import FullSizeCenter from '../FullSizeCenter';
import ServerError from './ServerError.svg?react';
import ClientError from './ClientError.svg?react';
import Forbidden from './Forbidden.svg?react';
import NotFound from './NotFound.svg?react';

const STATUS_CODE_TO_COMPONENT={
    400:ClientError,
    403:Forbidden,
    404:NotFound,
    500:ServerError
};

const GENERAL_ERROR_MESSAGE='请求时出现错误';

const  STATUS_CODE_TO_MESSAGE={
    400:GENERAL_ERROR_MESSAGE,
    403:'无权限',
    404:'找不到指定页面',
    500:'未知的服务端错误',
}

interface Props{
    type?:'500' | '400' | '403' | '404';
    message?:string;
    displayInDetail?:boolean;
    className?:string;
};

export default function Error({type='400',message,displayInDetail,className}:Props){
    const [expand,toggle]=useToggle(false);
    const errorMessage = displayInDetail ? GENERAL_ERROR_MESSAGE : message;
    return (
        <FullSizeCenter style={{flexDirection:'cloumns'}}>
           <Empty 
            image={createElement(STATUS_CODE_TO_COMPONENT[type])}
            description={errorMessage ?? STATUS_CODE_TO_MESSAGE[type]}
            className={className}
           />
           {
               displayInDetail && (
                   <>
                      <Gap.Vertical factor={4} base={4} />
                      <Button type="link" onClick={toggle}>{expand ? '收起' : '查看详情'}</Button>
                      {
                          expand && (
                              <p style={{wordBreak:'break-all'}}>
                                {message}
                              </p>
                          )
                      }

                   <>
               )
           }
        </FullSizeCenter>
    )
}

 (4)FullSizeCenter/index.tsx

import styled from '@emotion/styled';
import fullSizeFlexCenter from '../css/flex';

const fullSizeCenter=styled.div`
${fullSizeFlexCenter}
`
export default fullSizeCenter;

(5)css/flex.ts

import {css} from '@emotion/react';

export const flexCenter =css`
display:flex;
align-items:center;
justify-content:center;
`

export const fullSizeFlexCenter =css`
${flexCenter}
width:100%;
height:100%;
min-height:inherit;
`

使用时,直接用封装好的边界组件来作为顶层组件来包裹其他组件,例如:

<Boundary.Loading >
   ...其他代码
</Boundary.Loading >

代码缺少几个状态码对应的svg,感兴趣的小伙伴自己可以找一下!!

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React项目添加搜索功能需要以下步骤: 1. 创建一个名为Search的组件:可以是函数式组件或者类组件。 2. 在Search组件的state添加一个searchTerm属性,用于存储用户输入的搜索关键词。 3. 在Search组件添加一个input元素,用于接收用户的输入,并通过onChange事件监听输入变化,将输入的值更新到searchTerm属性。 4. 在Search组件添加一个按钮或者表单,用于提交搜索请求。 5. 在Search组件添加一个handleSubmit函数,用于处理用户提交搜索请求的逻辑。在该函数,可以通过调用API或者直接在前端进行搜索数据的操作。 6. 将Search组件添加到需要实现搜索功能的页面。 7. 在需要展示搜索结果的组件,使用搜索结果数据渲染页面。 下面是一个基本的搜索功能示例: ```jsx import React, { useState } from "react"; function Search() { const [searchTerm, setSearchTerm] = useState(""); const handleChange = (e) => { setSearchTerm(e.target.value); }; const handleSubmit = (e) => { e.preventDefault(); // 处理搜索逻辑,比如调用API或者前端搜索操作 console.log("搜索关键词:" + searchTerm); }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" value={searchTerm} onChange={handleChange} /> <button type="submit">搜索</button> </form> </div> ); } export default Search; ``` 你可以将上述代码添加到你的React项目,然后在需要使用搜索功能的页面引入Search组件即可。记得根据实际需求进行相应的修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值