React.lazy + Susponse模拟异步组件功能

212 阅读1分钟

实现效果:

  • 异步组件要实现的功能,异步请求数据,请求完数据再挂载组件。没有加载完数据显示 loading 效果。
  • 可量化生产。

主要思路:

  • 可以使用 React.lazy 实现动态加载,那么可以先请求数据,然后再加载组件,这时候以 props 形式将数据传递给目标组件,实现异步效果。
/**
 * 
 * @param {*} Component  需要异步数据的component 
 * @param {*} api        请求数据接口,返回Promise,可以再then中获取与后端交互的数据
 * @returns 
 */
function AysncComponent(Component,api){
  const AysncComponentPromise = () => new Promise(async (resolve)=>{
    const data = await api()
    resolve({
      default: (props) => <Component rdata={data} { ...props}  />
        })
  })
  return React.lazy(AysncComponentPromise)
}

思路:

  • 用 AysncComponent 作为一个 HOC 包装组件,接受两个参数,第一个参数为当前组件,第二个参数为请求数据的 api 。
  • 声明一个函数给 React.lazy 作为回调函数,React.lazy 要求这个函数必须是返回一个 Promise 。在 Promise 里面通过调用 api 请求数据,然后根据返回来的数据 rdata 渲染组件,别忘了接受并传递 props 。

使用:


/* 数据模拟 */
const getData = () => {
  return new Promise((resolve) => {
    //模拟异步
    setTimeout(() => {
      resolve({
        name: "alien",
        say: "let us learn React!",
      });
    }, 1000);
  });
};

/* 测试异步组件 */
function Test({ rdata, age }) {
  const { name, say } = rdata;
  console.log("组件渲染");
  return (
    <div>
      <div> hello , my name is {name} </div>
      <div>age : {age} </div>
      <div> i want to say {say} </div>
    </div>
  );
}

/* 父组件 */
export default class Index extends React.Component {
  LazyTest = AysncComponent(
    Test,
    getData
  ); /* 需要每一次在组件内部声明,保证每次父组件挂载,都会重新请求数据 ,防止内存泄漏。 */
  render() {
    const { LazyTest } = this;
    return (
      <div>
        <Suspense fallback={<div>loading...</div>}>
          <LazyTest age={18} />
        </Suspense>
      </div>
    );
  }
}

效果:

  • 如上 name 和 say 都是数据交互获取的数据。
  • 组件只渲染了一次,实现了异步渲染的效果