在jsx中,我们一般使用&&
或者三目表达式来控制组件的渲染
// 使用三目表达式控制渲染哪个组件
{ hasKey? <TabBar />:<NoConnect />}
// 当只需要控制一个组件时,则可以使用&&运算符
{ hasKey && <TabBar /> }
当功能越来越复杂,jsx越来越庞大,这种写法多起来后,就严重影响了代码的可读性可维护性,一大堆的花括号,一大堆的三目表达式,一眼看过去非常的零乱。
于是,我便动手封装了一个替换三目表达式的组件
export default function IfElse({ condition, children }) {
const childArr = React.Children.toArray(children);
if(condition){
return _.get(childArr, "[0]", null);
}
return _.get(childArr, "[1]", null);
}
很简单,只有一个if
判断,使用后就像这样子
<IfElse condition={hasKey}>
<TabBar />
<NoConnect />
</IfElse>
看起来是不是要清爽很多,但是却有很大的安全隐患,之前React次级渲染中有提到过,逻辑代码将会优于组件先执行。这将导致本该是安全判断的前提代码失效,报出异常。
<IfElse condition={object && object.image}>
<img src={object.image} />
</IfElse>
上述代码的条件语句object && object.image
本是对image
属性的安全判断,但是在IfElse
组件中完全失效,object.image
取值语句优先组件执行,所以会报出异常。如果项目泛用IfElse
组件,那将导致无法预料的错误。(我立马从代码中删掉了IfElse
组件...)
由此可见,组件封装jsx逻辑的思路并不安全,那么还有其他办法嘛?
JSX-Control-Statements 就是解决这个问题的一个Babel
插件,它提供了诸如If、Choose、When、With、For
等逻辑控制组件,但是这些都并不是真正的组件,而是在Babel
编译阶段对其提供的组件进行转码成js
代码,从而实现的一系列控制组件。
比如上面的例子,改用If
组件写:
<If condition={object && object.image}>
<img src={object.image} />
</If>
JSX-Control-Statements
则会将其转译成这样
{
object && object.image?<img src={object.image} />:null
}
使用了js
三目运算符,所以避免了JSX
组件中安全判断不再安全的问题。
那么,如果要控制多个组件渲染呢?再改写下,上上面的组件
<Choose>
<When condition={ hasKey }>
<TabBar />
</When>
<Otherwise>
<NoConnect />
</Otherwise>
</Choose>
这里使用了Choose、When、Otherwise
三个组件,明显可以感觉到代码繁琐了很多,在处理多个组件渲染的时候,JSX-Control-Statements
也并不是很方便,经过转译后,只是一个简单的三目表达式
{ hasKey? <TabBar />:<NoConnect />}
在使用With、For
组件的时候,由于变量并未声明,所以ESlint将会报出错误
<For each="item" index="index" of={ items }>
<span key={ item.id }>{ index }. { item.title }</span>
</For>
如上,item、index
并未显式声明,虽然编译为js
后没有错误,但是会逼死强迫症。所以这里还需要搭配eslint-plugin-jsx-control-statements使用。
相对于编译时长的增加,个人觉得将简单的代码繁琐化更加让人诟病,要不要使用JSX-Control-Statements
主要还是取决个人喜好吧,反正也是编译成js
代码,对于运行结果并没有什么影响。