前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React Suspense + 自定义Hook开启数据请求新方式。

React Suspense + 自定义Hook开启数据请求新方式。

作者头像
ssh_晨曦时梦见兮
发布2020-04-11 21:05:57
1.6K0
发布2020-04-11 21:05:57
举报

过去

类组件

在React的类组件时代,请求数据的时机经常放在componentDidMount中,然后state中需要有一个变量记录当前是否正在请求接口,在请求的前后需要手动去改变这些状态,大概代码如下:

代码语言:javascript
复制
class App extends Component {
  state = {
    loading: false,
  }

  componentDidMount() {
    this.setState({
      data: null,
      loading: true,
    });
    axios.get('/api/test').then((data) => {
      this.setState({
        data,
        loading: false,
      });
    });
  }

  render() {
    return this.state.loading ? '正在加载中...' : (
      <Page data={data} />
    );
  }
}

复制代码

hook组件

自从React发布了Hook以来,这个组织代码逻辑的方式广受欢迎,在Hook时代我们可以把请求前后的loading状态变量在自定义hook中管理起来,代码示例:

代码语言:javascript
复制
const useRequest = (fn, dependencies = []) => {
  const [data, setData] = useState(defaultValue);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    
    fn()
      .then(res => {
        setData(res);
      })
      .finally(() => {
        setLoading(false);
      });
  }, dependencies);

  return { data, setData, loading };
};
复制代码
代码语言:javascript
复制
// App.js
function App() {
  const { loading, data } = useRequest(() => axios.get('/api/test'));
  return loading ? '正在加载中...' : (
    <Page data={data} />
  );
}

复制代码

未来

Suspense组件 + useSWR

React发布了Suspense以后,数据请求又有了新思路,我们可以在视图容器的外层包裹一层Suspense,在内部通过向外throw Promise的方式告知Suspense我们的组件还没有准备好,需要展示Loading状态。

具体的代码可以看这里:codesandbox.io/s/react-swr…

代码语言:javascript
复制
// Router.js
import React, { Suspense } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Spin } from "antd";
import Author from "./Pages/Author";
import Table from "./Pages/Table";
import Layout from "./Layout";

export default function App() {
  return (
    <Router>
      <Layout>
        <Suspense fallback={<Spin tip="正在拼命获取数据,请稍后..." />}>
          <Switch>
            <Route exact path="/">
              <Author />
            </Route>
            <Route exact path="/table">
              <Table />
            </Route>
          </Switch>
        </Suspense>
      </Layout>
    </Router>
  );
}

复制代码
代码语言:javascript
复制
// pages/Author
import React from "react";
import useSWR from "../use-swr";

export default function Author() {
  const { data } = useSWR("/api/user");

  return (
    <div>
      <span>Hello {data.userName}</span>
    </div>
  );
}
复制代码
代码语言:javascript
复制
import useSWR from "swr";
import fetcher from "./fetcher";

export default url => {
  return useSWR(url, fetcher, { suspense: true });
};
复制代码
代码语言:javascript
复制
// fetcher
const fetcher = url => {
  let responseData;

  switch (url) {
    case "/api/user":
      responseData = {
        userName: "ssh"
      };
      break;
    default:
      break;
  }

  return new Promise(resolve => {
    setTimeout(() => {
      resolve(responseData);
    }, 2000);
  });
};

export default fetcher;

复制代码

其实这个Demo中就是使用了swr这个库,对配置项进行了一个简单的封装,开启了suspense模式

第二项参数所需要的fetcher就是自己定义的返回promise的逻辑。

在这种Suspense模式下,我们可以轻松的实现Loading状态的管理,而且不需要在Page组件中再去关心和声明加载中的组件。

关于swr这个库的具体分析文章可以查看这篇:精读《Hooks 取数 - swr 源码》

这个Demo中在路由进入过后如果再次进入,数据会直接显示之前请求过的,你会发现这非常像Vue中的keep-alive带来的效果,这是因为swr这个库在suspense模式下默认做了数据的缓存,如果想要关掉它目前还没在文档中看到相应的配置。

自己实现简易的useSWR

代码语言:javascript
复制
// use-my-swr
import { useState, useEffect } from "react";

export default (url, fetcher) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    fetcher(url)
      .then(result => {
        setData(result);
      })
      .finally(() => {
        setLoading(false);
      });
  }, [url, fetcher]);

  if (loading) {
    throw Promise.resolve(null);
  } else {
    return { data };
  }
};

复制代码

其实和上面写的useRequest相比,就是在loading的时候向外抛出一个promise,其他并没有什么改变。

使用:

代码语言:javascript
复制
import React from "react";
import useSWR from "../use-my-swr";
import fetcher from "../fetcher";

export default function Author() {
  const { data } = useSWR("/api/user", fetcher);

  return (
    <div>
      <span>Hello {data && data.userName}</span>
    </div>
  );
}
复制代码

小结

这篇文章只是在Suspense到来之前的一点开胃前菜,在React的发展长河中,开发者经历了各种各样的写法,HOC、render-props、hook,其最终的目的其实还是让我们写的代码更加易于阅读和维护,让开发者越爽越好。

HookSuspense碰撞在一起,让组件内部的逻辑和请求、等待内部的状态彻底解耦开来了,相比以前的类组件,代码变的越来越精简。

期待React团队的进一步动作吧!

参考文章: React Concurrent 模式抢先预览上篇: Suspense the world 精读《Hooks 取数 - swr 源码》

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年11月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 过去
    • 类组件
      • hook组件
      • 未来
        • Suspense组件 + useSWR
          • 自己实现简易的useSWR
          • 小结
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档