博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【译】TypeScript中的React Render Props
阅读量:6291 次
发布时间:2019-06-22

本文共 5738 字,大约阅读时间需要 19 分钟。

原文链接:

和之前的文章一样,本文也要求你对render props有一些知识背景,如果没有可能会对你有很大的帮助。本文将会使用函数作为children的render props模式以及结合React的context API来作为例子。如果你想使用类似于render这样子的render props,那也只需要把下面例子的children作为你要渲染的props即可。


为了展示render props,我们将要重写之前文章的。这里先展示HOC的版本:

export interface InjectedCounterProps {  value: number;  onIncrement(): void;  onDecrement(): void;}interface MakeCounterProps {  minValue?: number;  maxValue?: number;}interface MakeCounterState {  value: number;}const makeCounter = 

( Component: React.ComponentType

) => class MakeCounter extends React.Component< Subtract

& MakeCounterProps, MakeCounterState > { state: MakeCounterState = { value: 0, }; increment = () => { this.setState(prevState => ({ value: prevState.value === this.props.maxValue ? prevState.value : prevState.value + 1, })); }; decrement = () => { this.setState(prevState => ({ value: prevState.value === this.props.minValue ? prevState.value : prevState.value - 1, })); }; render() { const { minValue, maxValue, ...props } = this.props; return (
); } };复制代码

HOC向组件注入了value和两个回调函数(onIncrement 和 onDecrement),此外还在HOC内部使用minValue和maxValue两个props而没有传递给组件。我们讨论了如果组件需要知道这些值,如何不传递props可能会出现问题,并且如果使用多个HOC包装组件,注入的props的命名也可能与其他HOC注入的props冲突。

makeCounter HOC将会被像下面这样重写:

interface InjectedCounterProps {  value: number;  onIncrement(): void;  onDecrement(): void;}interface MakeCounterProps {  minValue?: number;  maxValue?: number;  children(props: InjectedCounterProps): JSX.Element;}interface MakeCounterState {  value: number;}class MakeCounter extends React.Component
{ state: MakeCounterState = { value: 0, }; increment = () => { this.setState(prevState => ({ value: prevState.value === this.props.maxValue ? prevState.value : prevState.value + 1, })); }; decrement = () => { this.setState(prevState => ({ value: prevState.value === this.props.minValue ? prevState.value : prevState.value - 1, })); }; render() { return this.props.children({ value: this.state.value, onIncrement: this.increment, onDecrement: this.decrement, }); }}复制代码

这里有一些需要注意的变化。首先,injectedCounterProps被保留,因为我们需要定义一个props的interface在render props函数调用上而不是传递给组件的props(和HOC一样)。MakeCounter(MakeCounterProps)的props已经改变,加上以下内容:

children(props: InjectedCounterProps): JSX.Element;复制代码

这是render prop,然后组件内需要一个函数带上注入的props并返回JSX element。下面是它用来突出显示这一点的示例:

interface CounterProps {  style: React.CSSProperties;  minValue?: number;  maxValue?: number;}const Counter = (props: CounterProps) => (  
{injectedProps => (
{injectedProps.value}
)}
);复制代码

MakeCounter自己的组件声明变得简单多了;它不再被包装在函数中,因为它不再是临时的,输入也更加简单,不需要泛型、做差值和类型的交集。它只有简单的MakeCounterProps和MakeCounterState,就像其他任何组成部分一样:

class MakeCounter extends React.Component<  MakeCounterProps,   MakeCounterState>复制代码

最后,render()的工作也变少了;它只是一个函数调用并带上注入的props-不需要破坏和对象的props扩展运算符展开了!

return this.props.children({  value: this.state.value,  onIncrement: this.increment,  onDecrement: this.decrement,});复制代码

然后,render prop组件允许对props的命名和在使用的灵活性上进行更多的控制,这是和HOC等效的一个问题:

interface CounterProps {  style: React.CSSProperties;  value: number;  minCounterValue?: number;  maxCounterValue?: number;}const Counter = (props: CounterProps) => (  
{injectedProps => (
Some other value: {props.value}
{injectedProps.value}
{props.minCounterValue !== undefined ? (
Min value: {props.minCounterValue}
) : null} {props.maxCounterValue !== undefined ? (
Max value: {props.maxCounterValue}
) : null}
)}
);复制代码

有了所有这些好处,特别是更简单的输入,那么为什么不一直使用render props呢?当然可以,这样做不会有任何问题,但要注意render props组件的一些问题。

首先,这里有一个关注点以外的问题;MakeCounter组件现在被放在了Counter组件内而不是包装了它,这使得隔离测试这两个组件更加困难。其次,由于props被注入到组件的渲染函数中,因此不能在生命周期方法中使用它们(前提是计数器被更改为类组件)。

这两个问题都很容易解决,因为您可以使用render props组件简单地生成一个新组件:

interface CounterProps extends InjectedCounterProps {  style: React.CSSProperties;}const Counter = (props: CounterProps) => (  
{props.value}
);interface WrappedCounterProps extends CounterProps { minValue?: number; maxValue?: number;}const WrappedCounter = ({ minValue, maxValue, ...props}: WrappedCounterProps) => (
{injectedProps =>
}
);复制代码

另一个问题是,一般来说,它不太方便,现在使用者需要编写很多样板文件,特别是如果他们只想将组件包装在一个单独的临时文件中并按原样使用props。这可以通过从render props组件生成HOC来补救:

import { Subtract, Omit } from 'utility-types';import MakeCounter, { MakeCounterProps, InjectedCounterProps } from './MakeCounter';type MakeCounterHocProps = Omit
;const makeCounter =

( Component: React.ComponentType

): React.SFC

& MakeCounterHocProps> => ({ minValue, maxValue, ...props}: MakeCounterHocProps) => (
{injectedProps =>
}
);复制代码

在这里,上一篇文章的技术,以及render props组件的现有类型,被用来生成HOC。这里唯一需要注意的是,我们必须从HOC的props中移除render prop(children),以便在使用时不暴露它:

type MakeCounterHocProps = Omit
;复制代码

最后,HOC和render props组件之间的权衡归结为灵活性和便利性。这可以通过首先编写render props组件,然后从中生成HOC来解决,这使使用者能够在两者之间进行选择。这种方法在可重用组件库中越来越常见,例如优秀的render-fns库。

就TypeScript而言,毫无疑问,hocs的类型定义要困难得多;尽管通过这两篇文章中的示例,它表明这种负担是由HOC的提供者而不是使用者承担的。在使用方面,可以认为使用HOC比使用render props组件更容易。

在react v16.8.0之前,我建议使用render props组件以提高键入的灵活性和简单性,如果需要,例如构建可重用的组件库,或者对于简单在项目中使用的render props组件,我将仅从中生成HOC。在react v16.8.0中释放react hook之后,我强烈建议在可能的情况下对两个高阶组件或render props使用它们,因为它们的类型更简单。

转载地址:http://yruta.baihongyu.com/

你可能感兴趣的文章
白帽子守护网络安全,高薪酬成大学生就业首选!
查看>>
ARM想将芯片装进人类大脑 降低能耗是一大挑战
查看>>
Oracle数据库的备份方法
查看>>
Selenium 自动登录考勤系统
查看>>
关于如何以编程的方式执行TestNG
查看>>
智能照明造福千家万户 家居智能不再是梦
查看>>
物联网如何跳出“看起来很美”?
查看>>
浅谈MySQL 数据库性能优化
查看>>
《UNIX/Linux 系统管理技术手册(第四版)》——1.10 其他的权威文档
查看>>
灵动空间 创享生活
查看>>
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.6 UDP回射客户程序:dg_cli函数...
查看>>
不要将时间浪费到编写完美代码上
查看>>
《算法基础:打开算法之门》一3.4 归并排序
查看>>
高德开放平台开放源代码 鼓励开发者创新
查看>>
《高并发Oracle数据库系统的架构与设计》一2.5 索引维护
查看>>
Firefox 是 Pwn2own 2014 上攻陷次数最多的浏览器
查看>>
阿里感悟(十八)- 应届生Review
查看>>
话说模式匹配(5) for表达式中的模式匹配
查看>>
《锋利的SQL(第2版)》——1.7 常用函数
查看>>
jquery中hover()的用法。简单粗暴
查看>>