React中的设计模式 - Prop Getters

本文探讨了在React中如何通过getProps设计模式让组件使用者更主动地控制props。通过示例展示了如何在Switch和Button组件中使用getTogglerProps方法获取和定制属性,包括处理onClick事件的通用方法callAll。getProps使得组件更具通用性和扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近开始学习React,跟着Kent学,有很多干货,这里分享Rect中的一个模式或者方法getProps

这里还是讨论props传递的问题,之前React中的设计模式 - 组合组件(上) 以及React中的设计模式 - 组合组件(下) 已经讨论过很多模式,本文讨论getProps

让组件使用者调用props, 而不是被动从父组件接受props

文章中完整的示例代码可以查看 这里


一、background

之前讨论的几种设计模式,本质上都是父组件给子组件传递属性,子组件没有获取属性的主动权,很多时候组件使用者其实更清楚需要什么属性,把属性的获得权交给使用者往往更容易给组件扩展新功能

于是,不妨设计出以下API,component可以通过getProps的主动获取父组件属性

<Component {...getProps({property_A, property_b})} />

二、原型

2.1 example

为了getProps的使用,不妨使用tonggle组件的例子

其中,App设计大概如下,on是组件的开关,

  1. Switch组件需要获取on属性
  2. button组件需要重写onClick属性,并且加入aria-label以及id的属性
function useToggle() {
  const [on, setOn] = React.useState(false)
  let toggle = () => setOn(!on)
  const getTogglerProps = (params) => {
	// 待实现
    }
  }
  return {on, toggle, getTogglerProps}
}

function App() {
  const {on, getTogglerProps} = useToggle()
  return (
    <div>
      <Switch {...getTogglerProps({on})} />
      <hr />
      <button
        {...getTogglerProps({
          'aria-label': 'custom-button',
          onClick: () => console.info('onButtonClick'),
          id: 'custom-button-id',
        })}
      >
        {on ? 'on' : 'off'}
      </button>
    </div>
  )
}

2.2 实现

根据以上的要求,getTogglerProps的实现就是获得从用户中获得属性,如果用户没有提供属性,那么就使用default的属性,于是实现如下

  const getTogglerProps = (params) => {
    if (params.onClick) {
      toggle = () => {
        setOn(!on)
        params.onClick()
      }
    }
    return{
      'aria-pressed': on,
      ...params,
      onClick: toggle
    }
  }

可以注意到,对于onClick的实现是略有复杂,具体就是因为onClick优惠default的方法,如果用户也提供了方法,不用把default的方法覆盖掉,更好的做法是执行defualt的方法,并且执行用户传过来的方法

2.3 改进

上面对onClick方法的实现并没有很通用,能不能有更加通用的方法呢,比如实现一个方法传入default的方法以及用户的方法,就能同时执行呢?

onClick: callAll(onClick, toggle),

是可以有的,实现callAll其实不算太复杂

const callAll = (...fns) => (...args) => fns.forEach(fn => fn?.(...args))

于是,全部代码如下

import * as React from 'react'
import {Switch} from '../switch'

const callAll = (...fns) => (...args) => fns.forEach(fn => fn?.(...args))

function useToggle() {
  const [on, setOn] = React.useState(false)
  const toggle = () => setOn(!on)

  function getTogglerProps({onClick, ...props} = {}) {
    return {
      'aria-pressed': on,
      onClick: callAll(onClick, toggle),
      ...props,
    }
  }

  return {
    on,
    toggle,
    getTogglerProps,
  }
}

function App() {
  const {on, getTogglerProps} = useToggle()
  return (
    <div>
      <Switch {...getTogglerProps({on})} />
      <hr />
      <button
        {...getTogglerProps({
          'aria-label': 'custom-button',
          onClick: () => console.info('onButtonClick'),
          id: 'custom-button-id',
        })}
      >
        {on ? 'on' : 'off'}
      </button>
    </div>
  )
}

export default App


总结

getProps是一个很好的的设计理念,可以让用户拥有更多的主动权,这样设计出来的组件也会更加通用;在设计组件的时候,如果是通用型组件,不妨提供getProps的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值