XIANFESchool / FE-problem-collection

前端问题收集和知识经验总结

Home Page:https://github.com/ShuyunXIANFESchool/FE-problem-collection/issues

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React JSX 中的条件判断

hjzheng opened this issue · comments

在书写 JSX 时,经常会有一类需求,就是在特定条件下 render 一些组件。
例如:

  • 显示警告信息时
{this.showMessage && <Message type={'warning'} />}
  • 加载表格数据时
{this.loading ? <Loading /> : <Table />}

这里,我使用 JavaScript 表达式进行处理,这样做,从代码的可读性和可维护性上看起来都还不错。

继续增加复杂度

{ show && (isAdmin || hasPermission) && <Dialog /> }

继续增加复杂度

{ isShow && configDataIsDone && (isAdmin || hasPermission) && <Dialog /> }

显而易见,随着复杂度的增加,代码的可读性变的很差,可维护性也变的不好。

此时,最简单的处理方式,创建一个 helper 函数

canShowDialog () {
    const { isShow, configDataIsDone, isAdmin, hasPermission } = this.props;
    return isShow && configDataIsDone && (isAdmin || hasPermission);
}
... ...
{ this.canShowDialog() && <Dialog /> }

或者创建一个 getter

get canShowDialog () {
    const { isShow, configDataIsDone, isAdmin, hasPermission } = this.props;
    return isShow && configDataIsDone && (isAdmin || hasPermission);
}
... ...
{ this.canShowDialog && <Dialog /> }

当然,有些时候,也可以依赖一些第三方库
例如 render-if

const { isShow, configDataIsDone, isAdmin, hasPermission } = this.props;
const canShowDialog = renderIf(isShow && configDataIsDone && (isAdmin || hasPermission));
... ...
{ this.canShowDialog(<Dialog />) }

还可以使用高阶组件
react-only-if

const { isShow, configDataIsDone, isAdmin, hasPermission } = this.props;
const DialogOnlyIf = onlyIf(({isShow, configDataIsDone,  isAdmin, hasPermission}) => {
     return isShow && configDataIsDone && (isAdmin || hasPermission);
})(<Dialog />);
... ...
{ <DialogOnlyIf isShow={...} configDataIsDone={...} isAdmin={...} hasPermission={...} /> }

即使这样,可读性上还是稍差点,不可否认通用编程语言在功能上,远大于模板,毕竟模板只是 DSL,针对特定领域的语言,在某些点上的能力毕竟有限,因为它是针对特定领域的,所以在特定领域的可读性和易用上要好于通用编程语言。

想象一下, 我们可不可以增加一些条件组件,参考一下 AngularJS1.x:

例如:

<div ng-if=“true”>要显示内容</div>

将组件设计成这样:

<If condition={isShow && configDataIsDone && (isAdmin || hasPermission)}>
     <Dialog />
</If>

其他组件 参考 ng-switch (else 和 else If 可以用 switch 代替)

<If condition={...}>
   {'if语句'}
</If>
<Switch>
     <When condition={...}>...</When>
     <When condition={...}>...</When>
     <Default>....</Default>
</Switch>

庆幸的是,有第三方的库可以进行支持,目前我所知道的有两个库:
react-if
jsx-control-statements

以 jsx-control-statements 为例:

{/* if语句 */}
<If condition={ test }>
  <span>Truth</span>
</If>

{/* switch 语句 */}
<Choose>
  <When condition={ test1 }>
    <span>IfBlock</span>
  </When>
  <When condition={ test2 }>
    <span>ElseIfBlock</span>
    <span>Another ElseIfBlock</span>
    <span>...</span>
  </When>
  <Otherwise>
    <span>ElseBlock</span>
  </Otherwise>
</Choose>

{/* for 循环 */}
 <For each="item" index="idx" of={ [1,2,3] }>
    <span key={ idx }>{ item }</span>
    <span key={ idx + '_2' }>Static Text</span>
  </For>

先赞一个,想法非常好👍
不过 jsx 的拥趸们估计要坐不住了:
『什么竟然说 JSX 不如模板语法?!!』
『你这跟写模板有什么区别,JSX 才是正道,你这个异教徒!』
『这么写简直是在开倒车!!』
哈哈哈哈(逃