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 #28

Open
SiZapPaaiGwat opened this issue Feb 4, 2016 · 4 comments
Open

Better React #28

SiZapPaaiGwat opened this issue Feb 4, 2016 · 4 comments

Comments

@SiZapPaaiGwat
Copy link
Owner

Better React

使用Ractive(一个MVVM框架)编写组件的时候,我就经常想获取用户当前传入的attributes。
很无奈,Ractive并不支持此功能。为此我还专门提过一个issue
React开始流行的时候,作为MVVM的爱好者我其实是比较抵触的。
后来发现势头不太对,感觉还是有必要了解下。
于是就抱着试一试的心理,开始了React的学习历程。
依稀记得当我首次接触props和state这对兄弟的时候,我的内心是十分激动的。

随着React学习的愈发深入,就愈发觉得掌握props和state的使用,对于掌握React整个基础体系是有多么重要。
今天本文就结合我自己的开发实践,讲讲使用props的一个基本原则。当然如果有更好的实践方法,烦请多交流。

一个典型

let Component = React.createClass({
  render() {
    let handleClick = () => {
      console.log('click handled')
    }
    return (
      <SubComponent onClick={handleClick} />
    )
  }
})

通常来说,子组件依赖父组件的某些变量、状态,或者需要更新父组件的UI这种需求还是很普遍的。
上例中父组件将一个handleClick函数作为prop传入给子组件,handleClick由于其作用域的天然优势可以将子组件的依赖问题层层化解,异常的简单方便。
这种将函数作为props传入子组件解决依赖问题的处理方式,也是目前React父子组件通信处理中一种非常普遍且流行的方式。

但是既然以此为例,那它肯定是反面典型了!

思考

下面我们以一个稍微复杂点的例子来看看这种处理方式的缺陷, 查看演示效果
试试点击演示中的Add按钮,然后查看控制台输出。

你会发现每点一次,底层的DumbCompoent的render都会触发一次。
照理说DumbComponent没有任何的props的变更应该不会rerender,为什么呢?
因为SmartComponent中传递prop的时候传递的是一个匿名函数,
DumbComponent在shouldComponentUpdate判断的时候由于onClick的引用不同而返回true。

如何修复呢?
很自然的你可能会想到将onClick这个函数缓存起来,这样引用就不会一直变了。
仔细思考一番其实这个方式并不可取,主要是因为:

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

解决方案

避免将函数作为props传递,使用EventEmitter来对父子组件的依赖解耦。

如果不了解EventEmitter,可以看看这篇文章
浏览器端的实现我推荐EventEmitter3

总结

为了避免不必要的麻烦,请不要将函数传入props中,取而代之使用EventEmitter。
遵循此原则,props始终传递基本类型或者只包含基本类型的对象。
在今后的React学习之路上,当你了解ImmutableJS时,这个原则将会让你深深受益。

@readyou
Copy link

readyou commented Apr 5, 2016

能给个例子吗?

@readyou
Copy link

readyou commented Apr 5, 2016

https://segmentfault.com/a/1190000004628682 这里说:必须不允许出现观察者模式,如自定义addEventListener方法,或on, fire等。这是不是与使用EventEmitter矛盾呢?

@SiZapPaaiGwat
Copy link
Owner Author

@readyou
这个规范大部分我倒是赞同,不过也有很多有争议的地方。
有些实施起来其实不太人性化,比如方法的书写顺序,这个之前我也这么设置过但写起来真的烦人。
还有就是所有依赖都使用props传递进来这个也要分实际情况,你可以看我的第二篇 #31 有讨论这个点。
还有他这个规范最重要的一点就是Container Component和Presentational Component 没有提到。
至于观察者模式的话其实一般情况确实用不到,如果你的组件有一定的通用性,比如下拉框,分页这种。
这里 #31 也有总结。
至于必须不允许出现观察者模式,我觉得绝对了,只能代表他们内部的解决方法的态度,在React社区我还没见过类似的观点,最多只是有人觉得这样的话不太“React”。

@SiZapPaaiGwat
Copy link
Owner Author

@readyou
例子可以看下这个组件:https://github.com/DataEye/static/blob/master/assets/tracking/components/mixed_panel/container.jsx
不过最新的代码我们迁移到coding了,最新的功能比这个更复杂,这个是很早之前的。
你可以看下如果不用EventEmitter我们的props得有多长,还有就是就像这个规范说的,你得为可选的回调事件设置默认值_.noop,这样其实没什么必要。

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