IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    在React Native中函数式的控制Loading Component

    Ashes Born\'s Blog发表于 2024-09-05 22:21:00
    love 0
    • 阅读前你需要知道的
    • 为什么需要函数式的控制LoadingComponent
    • 要解决的问题
    • 实现
      • 设计思路
      • 代码

    阅读前你需要知道的#

    • React Context是什么
    • 如何自定义Hooks

    为什么需要函数式的控制LoadingComponent#

    在APP的开发中,我们经常会遇到一些异步的操作,比如通过网络请求获取数据。在用户进行这类操作的时候,一般需要弹出一些提示的组件,用来表示这次网络请求所处的状态。最简单的实现方法是维护一个内部State,在网络请求的状态发生变化的时候,按照业务需求同步更新这个内部状态,并且根据这个状态来决定LoadingComponent是否渲染,代码示例如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const TestLoading = () => {
    const [isError, setIsError] = useState(false)
    const handleRequest = async () => {
    try {
    await requestAPI()
    setIsError(false)
    }catch(e){
    setIsError(ture)
    }
    }
    return (
    <>
    <Button title='request' onPress={handleRequest} />
    <Modal visible={isError}>
    <ActivityIndicator size="large"/>
    </Modal>
    </>
    )
    }

    从上面的代码我们不难看出,如果使用和这种简单的实现方式,需要在每个需要展示LoadingComponent的页面,手动添加它,并且还需要增加一个内部状态来控制它的展示。这不免显得有些冗余,如果过我们可以使用如下的函数式的调用方式来控制LoadingComponent,将大量减少冗余代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    const TestLoading = () => {
    //...
    const handleRequest = async () => {
    showLoading()
    await requestAPI()
    closeLoading()
    }
    //...
    return (
    <Button title='request' onPress={handleRequest} />
    )
    }

    要解决的问题#

    1. 和web不同的是,在Mobile的开发中,我们无法直接调用类似UIView这类的原生方法来增加新的Element
    2. 保持最大的兼容性,尽量不依赖Mobile平台提供的特殊API

    实现#

    设计思路#

    对于这样的LoadingComponent在整个APP中可以只存在一个这样的组件,并将它在APP的最外层进行挂载,然后在通过ReactContext共享它的控制渲染的函数。这样,我们就可以在任意一个组件或者Hook中控制LoadingComponent了。

    代码#

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    // GlobalLoaidngProvider.tsx
    export const GlobalLoadingContext = React.createContext({
    show: console.log
    close: console.log
    });

    export const GlobalLoadingProvider: React.FC<React.PropsWithChildren> = ({
    children
    }) => {
    const [isShow, setIsShow] = useState(false);
    const [message, setMessage] = useState('');
    const handleShow = (message?: string) => {
    setIsShow(true);
    message && setMessage(message);
    }
    const handleClose = () => {
    setIsShow(false)
    }
    return (
    <GlobalLoadingContext.Provider value={{
    show: handleShow,
    }}>
    {children}
    <Modal
    animationType="slide"
    transparent={true}
    visible={modalVisible}
    >

    <ActivityIndicator size='large' />
    <Text>{message}</Text>
    </Modal>
    </GlobalLoadingContext.Provider>
    )
    }

    // App.tsx
    // ...
    const App = () => {
    //...
    return (
    <GlobalLoadingProvider>
    {//... you component}
    </GlobalLoadingProvider>
    )
    }

    //RequestAPIButton.tsx

    const RequestAPI = () => {
    const {show, close} = useContext(GlobalLoadingContext)
    const handleRequest = async () => {
    show("data lading");
    await requestAPI();
    close();
    };

    return(
    <Button onPress={handleRequest} title="requestAPI" />
    )
    }


沪ICP备19023445号-2号
友情链接