最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 同学,请专业点,用Hooks解耦UI组件吧

    正文概述 掘金(卡颂)   2020-12-08   451

    你肯定看过(或写过)这样的渲染模式:

    1. 通过AJAX请求数据时渲染一个loading占位图标

    2. 当数据返回后重新渲染组件

    让我们一个使用Fetch API的简单例子:

    import React, { useState, useEffect } from 'react';
    
    const SomeComponent = (props) => {
      const [someData, setSomeData] = useState(null);
      const [loading, setLoading] = useState(false);
      const [error, setError] = useState(null);
      
      useEffect(() => {
        setLoading(true);
        fetch('/some-data')
          .then(response => response.json())
          .then(data => setSomeData(data))
          .catch(error => setError(error))
          .finally(() => setLoading(false));
      }, []);
      
      return (
        <React.Fragment>
          {loading && <div>{'Loading...'}</div>}
          {!loading && error && <div>{`Error: ${error}`}</div>}
          {!loading && !error && someData && <div>{/* INSERT SOME AMAZING UI */}</div>}
        </React.Fragment>
      );
    };
    

    当我们的应用逐渐庞大,假设有n个组件要使用同样的数据。

    为了减少重复请求,我决定使用LocalStorage缓存服务端数据。

    这是否意味着同样的渲染逻辑要重复写n次呢?

    解耦数据请求

    怎么可能,让我们将数据请求部分抽离为一个自定义hook——useSomeData

    import React, { useState, useEffect } from 'react';
    
    const useSomeData = () => {
      const cachedData = JSON.parse(localStorage.getItem('someData'));
      const [someData, setSomeData] = useState(cachedData);
      const [loading, setLoading] = useState(false);
      const [error, setError] = useState(null);
      
      useEffect(() => {
        if (!someData) {
          setLoading(true);
          fetch('/some-data')
            .then(response => response.json())
            .then(data => {
              localStorage.setItem('someData', JSON.stringify(data));
              return setSomeData(data);
            })
            .catch(error => setError(error))
            .finally(() => setLoading(false));
        }
      }, []);
      
      return { someData, loading, error };
    };
    

    使用useSomeData看起来像这样:

    const SomeComponent = (props) => {
      const { someData, loading, error } = useSomeData();
      return (
        <React.Fragment>
          {loading && <div>{'Loading...'}</div>}
          {!loading && error && <div>{`Error: ${error}`}</div>}
          {!loading && !error && someData && <div>{/* INSERT SOME AMAZING UI */}</div>}
        </React.Fragment>
      );
    };
    
    const AnotherComponent = (props) => {
      const { someData, loading, error } = useSomeData();
      return (
        <React.Fragment>
          {loading && <div>{'Loading...'}</div>}
          {!loading && error && <div>{`Error: ${error}`}</div>}
          {!loading && !error && someData && <div>{/* INSERT ANOTHER AMAZING UI */}</div>}
        </React.Fragment>
      );
    };
    

    复用代码挺棒的,但就仅此而已吧?

    定制数据请求

    我们的应用越来越复杂,我决定上Redux

    此时只需要简单的修改下useSomeData,完全不需要改动业务组件:

    import React, { useEffect } from 'react';
    import { useDispatch, useSelector } from 'react-redux';
    import { selectSomeData } from 'path/to/data/selectors';
    import { fetchSomeData } from 'path/to/data/action';
    
    const useSomeData = () => {
      const dispatch = useDispatch();
      const someData = useSelector(selectSomeData);
      const [loading, setLoading] = useState(false);
      const [error, setError] = useState(null);
      
      useEffect(() => {
        if (!someData) {
          setLoading(true);
          dispatch(fetchSomeData())
            .catch(error => setError(error))
            .finally(() => setLoading(false));
        }
      }, []);
      
      return { someData, loading, error }; 
    };
    

    某天我决定赶时髦上GraphQL。同样,只需要简单修改useSomeData而无需改动业务组件:

    import { gql, useQuery } from '@apollo/client';
    
    const FETCH_SOME_DATA = gql`
      fetchSomeData {
        data {
          # some fields
        }
      }
    `;
    
    const useSomeData = () => {
      const { data, loading, error } = useQuery(FETCH_SOME_DATA);
      return { someData: data, loading, error }; 
    };
    

    每当我自愿(或被迫)修改数据请求/状态管理部分时,只需要修改对应的hook就行。

    就像经典的依赖倒置原则(SOLID中的D)。尽管并非面向对象,但我们定义了一个抽象接口,并基于其实现了该接口的类。

    useSomeData实际上为使用他的业务组件提供了一个接口。

    开发者不需要关心useSomeData的实现原理,只需要关注接收到的数据、加载状态、错误信息即可。

    理论上来说,只要定义合适的接口,就能将UI从数据层解耦出来,并随时迁移到任何数据层上。


    起源地下载网 » 同学,请专业点,用Hooks解耦UI组件吧

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元