返回

React 中 Promise 的优雅用法,提升应用体验

前端

React 中优雅使用 Promise 的指南

在现代的 React 应用中,异步操作已成为常态。无论是网络请求、数据库查询还是任何其他长时间运行的任务,我们都必须处理它们。Promise 是 JavaScript 中处理异步操作的强大工具,它使我们能够获取结果或处理错误,而无需阻塞主线程。

使用 React 展示加载态和错误态

React 提供了内置功能,可以轻松地展示 Promise 的加载态和错误态,从而提升用户体验。

Suspense 组件允许我们在等待 Promise 完成时显示加载态。只要将 Promise 作为 Suspense 组件的子组件即可。例如:

import React, { useState, Suspense } from "react";

const MyComponent = () => {
  const [isLoading, setIsLoading] = useState(true);

  const fetchData = () => {
    setIsLoading(true);
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve("Data fetched");
        setIsLoading(false);
      }, 1000);
    });
  };

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <div>{fetchData()}</div>
    </Suspense>
  );
};

export default MyComponent;

ErrorBoundary 组件允许我们在 Promise 发生错误时显示错误态。与 Suspense 组件类似,只需将 Promise 作为 ErrorBoundary 组件的子组件即可。例如:

import React, { useState, ErrorBoundary } from "react";

const MyComponent = () => {
  const [isError, setIsError] = useState(false);

  const fetchData = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject("Error occurred");
      }, 1000);
    });
  };

  return (
    <ErrorBoundary>
      <div>{fetchData()}</div>
    </ErrorBoundary>
  );
};

export default MyComponent;

React Router 和 Promise

React Router 是一个流行的路由库,它提供了 useFetch() 钩子,可以轻松地将首屏网络请求与 Promise 结合起来。

import React, { useEffect, useState } from "react";
import { useFetch } from "react-router";

const MyComponent = () => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      const response = await useFetch("/api/data");
      setData(response.data);
      setIsLoading(false);
    };

    fetchData();
  }, []);

  return (
    <div>
      {isLoading ? <div>Loading...</div> : <div>{data}</div>}
    </div>
  );
};

export default MyComponent;

重试请求

有时,我们可能需要重试失败的请求。我们可以使用 Promise.retry() 方法轻松实现这一点。

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Error occurred");
    }, 1000);
  });
};

const retryFetchData = async () => {
  try {
    await fetchData();
  } catch (error) {
    // Retry the request
    await retryFetchData();
  }
};

状态管理

状态管理库,如 Redux,可以帮助我们维护 Promise 的加载态和错误态。

const initialState = {
  isLoading: false,
  isError: false,
  data: null,
};

const reducer = (state, action) => {
  switch (action.type) {
    case "FETCH_DATA_START":
      return {
        ...state,
        isLoading: true,
      };
    case "FETCH_DATA_SUCCESS":
      return {
        ...state,
        isLoading: false,
        data: action.payload,
      };
    case "FETCH_DATA_ERROR":
      return {
        ...state,
        isLoading: false,
        isError: true,
      };
    default:
      return state;
  }
};

const store = createStore(reducer, initialState);

然后,我们可以在组件中使用 useSelector()useDispatch() 钩子来访问和更新状态。

import React, { useSelector, useDispatch } from "react";

const MyComponent = () => {
  const isLoading = useSelector((state) => state.isLoading);
  const isError = useSelector((state) => state.isError);
  const data = useSelector((state) => state.data);

  const dispatch = useDispatch();

  const fetchData = async () => {
    dispatch({ type: "FETCH_DATA_START" });

    try {
      const response = await fetch("/api/data");
      dispatch({ type: "FETCH_DATA_SUCCESS", payload: response.data });
    } catch (error) {
      dispatch({ type: "FETCH_DATA_ERROR" });
    }
  };

  return (
    <div>
      {isLoading ? <div>Loading...</div> : <div>{data}</div>}
      {isError && <div>Error occurred</div>}
      <button onClick={fetchData}>Refresh</button>
    </div>
  );
};

export default MyComponent;

结论

在 React 应用中使用 Promise 可以显著提升用户体验,帮助我们优雅地处理异步操作。React 提供了内置功能和实用工具来展示加载态和错误态,而状态管理库可以帮助我们维护 Promise 的状态。通过遵循最佳实践,我们可以构建健壮且响应迅速的 React 应用。

常见问题解答

  1. 如何处理并行 Promise?
    使用 Promise.all()Promise.race() 来处理多个 Promise。

  2. Promise 的 reject 和 throw 有什么区别?
    reject 是用于明确拒绝 Promise 的方法,而 throw 是用于在 Promise 的执行过程中引发错误。

  3. 如何取消 Promise?
    通过实现 AbortController 接口来取消 Promise。

  4. 如何获得 Promise 的当前状态?
    使用 Promise.resolve()Promise.reject()Promise.race() 来获取 Promise 的当前状态。

  5. 如何使用 Promise 进行异步编程?
    通过将异步操作封装在 Promise 中并使用 await 来使用 Promise 进行异步编程。