函数组件设计模式

  • 容器模式
    • 实现按条件执行Hooks
    • 使用render props模式复用UI逻辑
      首先,Hooks的一个重要规则:Hooks必须在顶层作用域调用,而不能放在条件判断、循环语句中,即Hooks必须被执行到

这个规则存在的原因是:React需要在函数组件内部维护所用到的Hooks状态

例子,对于一个对话框组件,通过visible属性来控制是否显示。

比如期望如下:

function UserInfoModal({ visible, userId, ...rest }) {

    if (!visible) return null

    const [data, loading, error] = useUser(userId)

    return (

        <Modal visible={visible} {...rest}>

        </Modal>

    )
}

可以看到,我们期望在visble为false时不显示内容,但是这样却通不过编译,因为useUser这个hook在return语句之后。

所以,我们需要一个使用容器模式来间接的实现条件逻辑

具体做法,就是在两个组件中添加一个条件判断

在UserInfoModal外层加一个容器
export default function UserInfoModalWrapper ({
    visible,
    ...rest // 使用rest获取除visible以外的所有属性
}) {
    if (!visible) return null
    return <UserInfoModal {...rest} />
}
把判断的条件放到Hooks中去

在容器模式中我们可以看到,条件的隔离对象是多个子组件,这意味着它通常用于一些比较大的逻辑的隔离,对于一些细节的控制,直接放到Hooks中进行判断。
比如当article获取到后再去获取作者。

  • 使用render props模式(即render作为props传入)
    • react中最重要的一个设计模式,解决UI逻辑复用的问题
    • 不仅适用于Class组件,也适用于函数组件

就是把一个render函数作为属性传递给某个组件,由这个组件去执行这个函数从而render实际的内容。

函数组件下,Hooks有一个局限,即只能用作数据逻辑的重用,对于UI表现逻辑的复用,最好使用render props。

首先,实现一个数据逻辑重用的简单例子:

import { useState, useCallback } from 'react'

function CounterRenderProps({ children }) {

    cosnt [count, setCount] = useState(0)

    const increment = useCallback(() => {

        setCount(count+1)

    }, [count])

    const decrement = useCallback(() => {

        setCount(count-1)

    },[count])

    return children({ count, increment, decrement })

}

function CounterRenderPropsExample() {

    <CounterRenderProps>

        {

            ({ count, increment, decrement } => {

                return (

                        <div>

                            // ...

                        </div>

                    )

            })

        }

    </CounterRenderProps>

}
  • 有UI逻辑重用的例子

    1. 比如,我们需要显示一个列表,如果超过一定数量,则把多余的部分折叠起来,通过一个弹出框去显示。
    2. 实现一个表格,也是显示前五个,多余的折叠到更多里面。

在这里插入图片描述

分析一下:

功能相同的部分是,数据超过一定数量,显示一个more的文字,鼠标移上去,则弹出一个框,用于显示其他数据

功能不同的部分:每一个列表项如何渲染,是在使用的时候决定的。

import { Popver } from 'antd'

function ListWithMore({ renderItem, data=[], max }) {
    const elements = data.map((item, index) => renderItem(item, index, data))
    const show = elements.slice(0,max)
    const hide = elements.slice(max)
    return (
        <span>
            {show}
            {
             hide.length > 0 && (
                 <Popver>
                     <span>
                         and {" "}
                         <span>{hide.length} more...</span>
                     </span>
                 </Popver>
             )
            }
        </span>
    )
}

可以看到,组件接收了三个参数,分别是:

  1. renderItem:用于接收一个函数,由父组件决定如何渲染一个列表项;
  2. data:需要渲染的数据;
  3. max:最多显示几条数据。
    下面代码展示了上面示意图中两个场景的实现代码:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值