MST
星途 面试题库

面试题:React高阶组件封装API请求的边界情况处理与扩展性

在使用高阶组件封装API请求时,会遇到各种边界情况,例如网络异常、请求超时、API接口变更等。假设当前项目已经使用高阶组件封装了大量API请求,现在需要增加对这些边界情况的处理,并且要保证系统有良好的扩展性。请详细描述你的设计思路,包括如何设计错误处理机制、如何在不影响现有业务逻辑的前提下增加新的处理逻辑,同时给出关键代码示例。
45.1万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 错误处理机制设计
    • 网络异常:使用window.navigator.onLine属性判断网络状态,在发起请求前进行检查。如果网络离线,直接抛出一个特定的网络异常错误。在请求过程中,如果发生网络错误(如fetchtype'network'),捕获并处理该错误。
    • 请求超时:在fetch请求时设置signal,通过AbortController实现超时控制。当超时时,终止请求并抛出超时错误。
    • API接口变更:在请求返回时,检查返回的状态码和数据结构。如果状态码不符合预期(如非200 - 299),或者数据结构与预期不符,抛出相应的错误。可以通过定义一套规范的错误码和错误信息,方便统一处理。
  2. 增加新处理逻辑且不影响现有业务逻辑
    • 采用装饰器模式:在高阶组件的基础上,使用装饰器函数来添加新的处理逻辑。这样可以将新的处理逻辑与原有的高阶组件逻辑解耦。每个装饰器负责处理一种特定的边界情况,如网络异常处理装饰器、请求超时处理装饰器等。
    • 配置化管理:将处理逻辑相关的配置(如超时时间、错误码映射等)提取到一个配置文件中,方便统一管理和修改。在高阶组件或装饰器中读取这些配置,以实现不同环境下的灵活配置。

关键代码示例

  1. 网络异常处理
// 检查网络状态的函数
function checkNetworkStatus() {
    if (!window.navigator.onLine) {
        throw new Error('Network is offline');
    }
}

// 网络异常处理装饰器
function withNetworkErrorHandling(WrappedComponent) {
    return function (props) {
        try {
            checkNetworkStatus();
        } catch (error) {
            // 处理网络异常,比如显示提示信息等
            console.error('Network error:', error.message);
            return null;
        }
        return <WrappedComponent {...props} />;
    };
}
  1. 请求超时处理
// 请求超时处理装饰器
function withTimeoutHandling(WrappedComponent, timeout = 5000) {
    return function (props) {
        const controller = new AbortController();
        const { signal } = controller;

        const timeoutId = setTimeout(() => {
            controller.abort();
        }, timeout);

        // 模拟API请求,这里用fetch举例
        const fetchData = async () => {
            try {
                const response = await fetch('your-api-url', { signal });
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const data = await response.json();
                return data;
            } catch (error) {
                if (error.name === 'AbortError') {
                    console.error('Request timed out');
                } else {
                    console.error('Fetch error:', error.message);
                }
                return null;
            }
        };

        // 在组件卸载时清除定时器
        useEffect(() => {
            return () => {
                clearTimeout(timeoutId);
            };
        }, []);

        // 调用API并传递数据给WrappedComponent
        const data = fetchData();
        return <WrappedComponent data={data} {...props} />;
    };
}
  1. 结合高阶组件使用示例
// 假设这是原有的高阶组件封装的API请求
function withAPIFetch(WrappedComponent, apiUrl) {
    return function (props) {
        const [data, setData] = useState(null);

        useEffect(() => {
            const fetchData = async () => {
                try {
                    const response = await fetch(apiUrl);
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    const result = await response.json();
                    setData(result);
                } catch (error) {
                    console.error('API fetch error:', error.message);
                }
            };
            fetchData();
        }, [apiUrl]);

        return <WrappedComponent data={data} {...props} />;
    };
}

// 使用装饰器和高阶组件
const MyComponent = ({ data }) => {
    return (
        <div>
            {data? <p>{JSON.stringify(data)}</p> : <p>Loading...</p>}
        </div>
    );
};

const EnhancedComponent = withNetworkErrorHandling(withTimeoutHandling(withAPIFetch(MyComponent, 'your-api-url'), 3000));