Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better React (2) #31

Open
SiZapPaaiGwat opened this issue Mar 12, 2016 · 2 comments
Open

Better React (2) #31

SiZapPaaiGwat opened this issue Mar 12, 2016 · 2 comments

Comments

@SiZapPaaiGwat
Copy link
Owner

之前重构项目后根据个人实战经验写了一篇《Better React》,总结在React中传递props应该注意的事项。
在后来与网友的讨论中发现行文总结不太严谨,于是乎再度发文,争取纠正其中某些纰漏之处,不至于误导他人。
如果你还没有阅读《Better React》,推荐阅读之后再来阅读本文。

缓存函数作为组件的prop传递不可取吗?

之前的文章中不推荐缓存函数主要是因为下面这两个原因:

  • 类似的prop越多,外层缓存的函数越多,代码风格极其不自然
  • 如果函数依赖于局部变量,缓存的方式异常麻烦甚至于无法解决

这里我们有必要再进行一些科普工作。 React组件可以接受函数作为prop,一般我们传递的时候有三种方式:

  1. 在组件当前作用域定义局部变量
  2. 在最外层的作用域定义全局变量
  3. 作为组件自身的实例方法定义

第一种方式写法最自然,但是危害最大,因为函数引用在父组件render的时候会一直变化。 第二种方式写法最蛋疼,函数引用不会变化,但是可以解决一些问题。
第三种方式则是前两种方法的一个比较完美结合。

至此,第一个原因提及的问题通过第三种方式可以解决。至于代码风格问题,因人而异。
第二个原因提到的问题可能描述的不太详细,以致于会有人疑惑:

  • 为什么不把依赖的变量作为prop一同传入给子组件,这样反而更符合React的思想

传还是不传,怎么做才是最佳实践?且往下看。

应该使用EventEmitter吗?

依赖是否需要作为props传递给子组件?这个我只能无奈地说要结合实际需求决定。
当我们不使用EventEmitter的时候,看看我们怎么处理下面三个比较复杂的场景:

_场景一_
假设多个父组件引用了同一子组件,父组件的依赖又各不相同,这种方式需要将依赖全部加入到子组件的props里,必然引起子组件props爆炸。
props爆炸带来的就是一堆无谓的propType约束定义以及执行时的非空判断,代码臭味非常明显。
倘若子组件未来再增加一些函数类型的props,这种方式简直就是灾难!
而EventEmitter只需要给子组件绑定所需的事件交给子组件自己在合适的时机触发就可以了。

_场景二_
少数情况我们要考虑事件解绑,而置空函数类型的props必然导致rerender。
当然你也可以通过设置开关变量来解决,但原本简单的逻辑变得更复杂了。
如果函数类型的props很多,开关变量的数目也不会少,徒增很多无意义的代码。
而EventEmitter只需要简单的解绑事件,也不会引起rerender。

_场景三_
在场景一的情况下,假设现在需要把子组件的事件处理结果同步到父组件的上级。
在我们重构代码的时候,这种方式需要修改所有的父组件的代码才能满足需求。
而EventEmitter只需要在最外层的组件给子组件绑定一个事件即可。

更多的例子我就不一一列举了,相信真实世界的案例会更加多变和复杂。不过我们基本可以看出,场景越复杂EventEmitter的优势越明显。
EventEmitter能够将组件之间的依赖层层解耦,从而能够从容的应对需求的不断变化。

什么情况下不应该使用EventEmitter?

首先我们必须承认,在开源的React组件中,使用EventEmitter非常少见。
为什么呢?我个人认为主要是以下几个原因:

  • 浏览器不像Node.js,没有原生的EventEmitter实现,需要引入额外的库来支持;
  • 开源组件一般功能和需求规划较为明确,变化相对较少,使用EventEmitter收益非常有限。

所以我推荐在功能通用或逻辑相对简单的组件中不必使用EventEmitter,而在功能复杂需求变化频繁的业务组件中优先使用EventEmitter。

@Thinking80s
Copy link

那么在实际的复杂项目中需要怎样使用EventEmitter?是否又会遇到其他的问题?

@SiZapPaaiGwat
Copy link
Owner Author

@Thinking80s 实际项目中肯定是要用到的,至于其他的我觉得不会有什么问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants