react之容器组件和展示组件相分离解密

JimYPNV 8年前
   <p>Redux 的 React 绑定库包含了 容器组件和展示组件相分离的开发思想。</p>    <p>明智的做法是只在最顶层组件(如路由操作)里使用 Redux。其余内部组件仅仅是展示性的,所有数据都通过 props 传入。</p>    <p>那么为什么需要容器组件和展示组件相分离呢?</p>    <p>这里有个基本原则:容器组件仅仅做数据提取,然后渲染对应的子组件,记住这个点,Trust me!</p>    <p>看下面这个展示列表的例子,不区分容器和展示组件的情况</p>    <pre>  <code class="language-javascript">// CommentList.js  class CommentList extends React.Component {    constructor() {      super();      this.state = { comments: [] }    }    componentDidMount() {      $.ajax({        url: "/my-comments.json",        dataType: 'json',        success: function(comments) {          this.setState({comments: comments});        }.bind(this)      });    }    render() {      return <ul> {this.state.comments.map(renderComment)} </ul>;    }    renderComment({body, author}) {      return <li>{body}—{author}</li>;    }  }</code></pre>    <p>可用性:CommentList不可以复用</p>    <p>数据结构:组件应该对所需要的数据有所预期,但这里其实没有,PropTypes可以很好的做到这一点</p>    <p>那么来看下分离的情况:</p>    <pre>  <code class="language-javascript">// CommentListContainer.js  class CommentListContainer extends React.Component {    constructor() {      super();      this.state = { comments: [] }    }    componentDidMount() {      $.ajax({        url: "/my-comments.json",        dataType: 'json',        success: function(comments) {          this.setState({comments: comments});        }.bind(this)      });    }    render() {      return <CommentList comments={this.state.comments} />;    }  }      // CommentList.js  class CommentList extends React.Component {    constructor(props) {      super(props);    }    render() {       return <ul> {this.props.comments.map(renderComment)} </ul>;    }    renderComment({body, author}) {      return <li>{body}—{author}</li>;    }  }</code></pre>    <p>这样就做到了数据提取和渲染分离,CommentList可以复用,CommentList可以设置PropTypes判断数据的可用性</p>    <p>来看下容器组件和展示组件的区别:</p>    <table>     <thead>      <tr>       <th>展示组件</th>       <th>容器组件</th>      </tr>     </thead>     <tbody>      <tr>       <td>关注事物的展示</td>       <td>关注事物如何工作</td>      </tr>      <tr>       <td>可能包含展示和容器组件,并且一般会有DOM标签和css样式</td>       <td>可能包含展示和容器组件,并且不会有DOM标签和css样式</td>      </tr>      <tr>       <td>常常允许通过this.props.children传递</td>       <td>提供数据和行为给容器组件或者展示组件</td>      </tr>      <tr>       <td>对第三方没有任何依赖,比如store 或者 flux action</td>       <td>调用flux action 并且提供他们的回调给展示组件</td>      </tr>      <tr>       <td>不要指定数据如何加载和变化</td>       <td>作为数据源,通常采用较高阶的组件,而不是自己写,比如React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()</td>      </tr>      <tr>       <td>仅通过属性获取数据和回调</td>      </tr>      <tr>       <td>很少有自己的状态,即使有,也是自己的UI状态</td>      </tr>      <tr>       <td>除非他们需要的自己的状态,生命周期,或性能优化才会被写为功能组件</td>      </tr>     </tbody>    </table>    <p>优势:</p>    <ul>     <li> <p>展示和容器更好的分离,更好的理解应用程序和UI</p> </li>     <li> <p>重用性高,展示组件可以用于多个不同的state数据源</p> </li>     <li> <p>展示组件就是你的调色板,可以把他们放到单独的页面,在不影响应用程序的情况下,让设计师调整UI</p> </li>     <li> <p>迫使你分离标签,达到更高的可用性</p> </li>    </ul>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000006845396</p>    <p> </p>