转载

React Mixins Are Dead in ES6

背景

Unfortunately, we will not launch any mixin support for ES6 classes in React. That would defeat the purpose of only using idiomatic JavaScript concepts.There is no standard and universal way to define mixins in JavaScript. In fact, several features to support mixins were dropped from ES6 today. There are a lot of libraries with different semantics. We think that there should be one way of defining mixins that you can use for any JavaScript class. React just making another doesn’t help that effort.

从 React官网 文档 v0.13 上我们可以看到, mixin 不再被ES6 所支持,希望以更加通用和标准的javascript 概念去取代它。

关于Mixins

很多时候,不同的组件可能需要使用到一些公共的方法,Minxins 可以包装这些公共的方法暴露给外部调用。很多情况下,我们会定义一些React生命周期的方法,React 会自动地帮我们把这些方法合并到component 内,这些方法也将被组件所调用。

但是,使用Mixins也会导致一些问题,主要有以下几个原因。

  • 组件和Mixins 之间的关系式隐式的,Mixins 的内部实现通常都会依赖组件内定义的方法,但对于Mixins 来说,很难知道该方法被定义在哪个组件中。

  • 如果一个组件中使用了多个Mixins,而不同Mixins却定义了相同的方法,这个时候就容易引起冲突。

  • Mixins 尝试往你的组件中添加更多的state,然而这并不是你想要的。 可参考 Why Flux Component is better than Flux Mixin

Higher-Order Components

Higher-Order Components是其中一种替代 Mixins 的其中一种解决方案,现在我们先来看一个 用 mixins 实现的触发 Flux Stores更新 State 的例子。

javascriptfunction StoreMixin(...stores) {   var Mixin = {     getInitialState() {       return this.getStateFromStores(this.props);     },     componentDidMount() {       stores.forEach(store =>         store.addChangeListener(this.handleStoresChanged)       );       this.setState(this.getStateFromStores(this.props));     },     componentWillUnmount() {       stores.forEach(store =>         store.removeChangeListener(this.handleStoresChanged)       );     },     handleStoresChanged() {       if (this.isMounted()) {         this.setState(this.getStateFromStores(this.props));       }     }   };   return Mixin; } 

在使用的时候,我们先把 StoreMixin 添加到mixins列表中,然后在组件中定义 getStateFromStores(props) 方法

javascriptvar UserProfilePage = React.createClass({   mixins: [StoreMixin(UserStore)],   propTypes: {     userId: PropTypes.number.isRequired   },   getStateFromStores(props) {     return {       user: UserStore.get(props.userId);     }   }   render() {     var { user } = this.state;     return <div>{user ? user.name : 'Loading'}</div>;   } 

这样,当UserProfilePage 在渲染的时候就会触发 StoreMixin 中定义的一些生命周期的方法,监听Store数据变化。变化之后触发响应的处理函数。

什么是 higher-order component ?

higher-order component 是一个接收一个组件,然后返回包装了该组件的另外一个新组件的函数。

嗯,听起来有点拗口,我们来举个例子看看就明白了。

javascriptfunction connectToStores(Component, stores, getStateFromStores) {   const StoreConnection = React.createClass({     getInitialState() {       return getStateFromStores(this.props);     },     componentDidMount() {       stores.forEach(store =>         store.addChangeListener(this.handleStoresChanged)       );     },     componentWillUnmount() {       stores.forEach(store =>         store.removeChangeListener(this.handleStoresChanged)       );     },     handleStoresChanged() {       if (this.isMounted()) {         this.setState(getStateFromStores(this.props));       }     },     render() {       return <Component {...this.props} {...this.state} />;     }   });   return StoreConnection; }; 

connectToStores 看起来有点像mixin ,但是和前面的 StoreMixin 不同。 StoreMixin 管理的是组件的内部 state。但是 connectToStores 却是把(Comment)组件包装起来,然后把props传递给它。这样,通过一种组件内嵌的良好方式,就把组件的生命周期隔离起来,不存在合并的问题。

推荐

ract-dnd 一个专注于控件拖拽的库,是基于 higher-order component 而实现。

正文到此结束
Loading...