{"id":239591,"date":"2016-03-21T06:03:40","date_gmt":"2016-03-21T13:03:40","guid":{"rendered":"http:\/\/css-tricks.com\/?p=239591"},"modified":"2017-04-12T06:56:35","modified_gmt":"2017-04-12T13:56:35","slug":"learning-react-container-components","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/learning-react-container-components\/","title":{"rendered":"Leveling Up With React: Container Components"},"content":{"rendered":"

This tutorial is the second of a three-part series on React by Brad Westfall<\/a>. This series is all about going beyond basic React skills and building bigger things, like entire Single Page Applications (SPAs). This article picks up where the last article, on React Router, left off.<\/em><\/p>\n

<\/p>\n

\n

Article Series:<\/h4>\n
    \n
  1. React Router<\/a><\/li>\n
  2. Container Components (You are here!)<\/strong><\/li>\n
  3. Redux<\/a><\/li>\n<\/ol>\n<\/div>\n

    In the first article<\/a>, we created routes and views. In this tutorial, we’re going to explore a new concept in which components don\u2019t create views, but rather facilitate the ones that do. There is code to follow along with at GitHub<\/a>, if you like to dive right into code.<\/p>\n

    We\u2019ll also be introducing data to our application. If you\u2019re familiar with with any sort of component-design or MVC patterns, you probably know that it\u2019s generally considered poor-practice to mix your views with application behavior. In other words, while views need to receive data to render it, they shouldn\u2019t know where the data came from, how it changes, or how to create it.<\/p>\n

    Fetching data with Ajax<\/h3>\n

    As an example of a poor practice, let\u2019s expand on our UserList<\/code> component from the previous tutorial to handle its own data fetching:<\/p>\n

    \/\/ This is an example of tightly coupled view and data which we do not recommend\r\n\r\nvar UserList = React.createClass({\r\n  getInitialState: function() {\r\n    return {\r\n      users: []\r\n    }\r\n  },\r\n\r\n  componentDidMount: function() {\r\n    var _this = this;\r\n    $.get('\/path\/to\/user-api').then(function(response) {\r\n      _this.setState({users: response})\r\n    });\r\n  },\r\n\r\n  render: function() {\r\n    return (\r\n      <ul className=\"user-list\">\r\n        {this.state.users.map(function(user) {\r\n          return (\r\n            <li key={user.id}>\r\n              <Link to=\"{'\/users\/' + user.id}\">{user.name}<\/Link>\r\n            <\/li>\r\n          );\r\n        })}\r\n      <\/ul>\r\n    );\r\n  }\r\n});<\/code><\/pre>\n

    If you need a more detailed\/beginner explanation of what this component is doing, see this explanation<\/a>.<\/p>\n

    Why is the example less than ideal?. To start, we\u2019ve broken the rule of mixing \u201cbehavior\u201d with \u201chow to render the view\u201d — the two things that should stay separate.<\/p>\n

    To be clear, there\u2019s nothing wrong with using getInitialState<\/code> to initialize component state, and there\u2019s nothing wrong with conducting an Ajax request from componentDidMount<\/code> (although we should probably abstract the actual call out to other functions). The problem is that we\u2019re doing these things together<\/em> in the same component where the view is stored. This tight-coupling makes the application more rigid and WET<\/a>. What if you need to fetch a list of users elsewhere too? The action of fetching users is tied down to this view, so it\u2019s not reusable.<\/p>\n

    The second problem is that we\u2019re using jQuery for the Ajax call. Sure, jQuery has many nice features, but most of them deal with DOM rendering and React has its own way of doing this. As for jQuery\u2019s non-DOM features like Ajax, chances are you can find lots of alternatives that are more single-feature focused.<\/p>\n

    One of those alternatives is Axios<\/a>, a promise-based Ajax tool that\u2019s very similar (in terms of API) to jQuery\u2019s promise-based Ajax features. How similar are they?<\/p>\n

    \/\/ jQuery\r\n$.get('\/path\/to\/user-api').then(function(response) { ... });\r\n\r\n\/\/ Axios\r\naxios.get('\/path\/to\/user-api').then(function(response) { ... });<\/code><\/pre>\n

    For the remaining examples, we\u2019ll continue to use Axios. Other similar tools include got<\/a>, fetch<\/a>, and SuperAgent<\/a>.<\/p>\n

    Props and State<\/h3>\n

    Before we get into Container and Presentational Components, we need to clear up something about props and state.<\/p>\n

    Props and state are somewhat related in the sense that they both \u201cmodel\u201d data for React components. Both of them can be passed down from parent to child components. However, the props and state of a parent component will become just props to their child component.<\/p>\n

    As an example, let\u2019s say ComponentA<\/strong> passes some of its props and state to its child, ComponentB<\/strong>. The render<\/code> method of ComponentA<\/strong> might look like this:<\/p>\n

    \/\/ ComponentA\r\nrender: function() {\r\n  return <ComponentB foo={this.state.foo} bar={this.props.bar} \/>\r\n}<\/code><\/pre>\n

    Even though foo<\/code> is \u201cstate\u201d on the parent, it will become a \u201cprop\u201d on the child ComponentB<\/strong>. The attribute for bar<\/code> also becomes a prop on the child component because all data passed from parent to child will become props in the child. This example shows how a method from ComponentB<\/strong> can access foo<\/code> and bar<\/code> as props:<\/p>\n

    \/\/ ComponentB\r\ncomponentDidMount: function() {\r\n  console.log(this.props.foo);\r\n  console.log(this.props.bar);\r\n}<\/code><\/pre>\n

    In the Fetching Data with Ajax<\/em> example, data received from Ajax is set as the component\u2019s state. The example doesn\u2019t have child components, but you can imagine if it did, the state would \u201cflow\u201d<\/a> down from parent to child as props.<\/p>\n

    To understand state better, see the React Documentation<\/a>. From here on, this tutorial will refer to the data that changes over time, as \u201cstate\u201d.<\/p>\n

    It\u2019s time to break up<\/h3>\n

    In the Fetching Data with Ajax<\/em> example, we created a problem. Our UserList<\/code> component works but it\u2019s trying to do too many things. To solve the problem, let\u2019s break the UserList<\/code> into two components that each serve a different role. The two component types will be conceptually called Container Components<\/strong> and Presentational Components<\/strong>, a.k.a. “smart” and “dumb” components.<\/p>\n

    In short, Container Components source the data and deal with state. State is then passed to Presentational Components as props and is then rendered into views.<\/p>\n

    The terms “smart” vs “dumb” components are going away in the community. I\u2019m only making reference to them here in case you read about them in older articles, so you\u2019ll know they\u2019re the same concept as Container vs Presentational.<\/p>\n

    Presentational Components<\/h4>\n

    You may not know it, but you\u2019ve already seen Presentation Components before in this tutorial series. Just imagine how the UserList<\/code> component looked before it was managing its own state:<\/p>\n

    var UserList = React.createClass({\r\n  render: function() {\r\n    return (\r\n      <ul className=\"user-list\">\r\n        {this.props.users.map(function(user) {\r\n          return (\r\n            <li key={user.id}>\r\n              <Link to=\"{'\/users\/' + user.id}\">{user.name}<\/Link>\r\n            <\/li>\r\n          );\r\n        })}\r\n      <\/ul>\r\n    );\r\n  }\r\n});<\/code><\/pre>\n

    It\u2019s not exactly<\/em> the same as before, but it is<\/em> a Presentational Component. The big difference between it and the original<\/a> is that this one iterates over user data to create list-items, and receives the user data via props.<\/p>\n

    Presentational Components are “dumb” in the sense that they have no idea how the props they received came to be. They have no idea about state.<\/p>\n

    Presentational Components should never change the prop data itself. In fact, any component that receives props should consider that data immutable and owned by the parent. While the Presentational Component shouldn\u2019t change the meaningfulness of the data in the prop, it can format the data for the view (such as turning a Unix timestamp into a something more human readable).<\/p>\n

    In React, events are attached directly to the view with attributes like onClick<\/code>. However, one might wonder how events work since Presentational Components aren\u2019t supposed to change the props. For that, we have a whole section on events below.<\/p>\n

    Iterations<\/h4>\n

    When creating DOM nodes in a loop, the key<\/code> attribute is required<\/a> to be something unique (relative to its siblings). Note that this is only for the highest level DOM node \u2014 the <li><\/code> in this case.<\/p>\n

    Also, if the nested return<\/code> looks funky to you, consider another approach which does the same thing by splitting the creation of a list item into its own function:<\/p>\n

    var UserList = React.createClass({\r\n  render: function() {\r\n    return (\r\n      <ul className=\"user-list\">\r\n        {this.props.users.map(this.createListItem)}\r\n      <\/ul>\r\n    );\r\n  },\r\n\r\n  createListItem: function(user) {\r\n    return (\r\n      <li key={user.id}>\r\n        <Link to=\"{'\/users\/' + user.id}\">{user.name}<\/Link>\r\n      <\/li>\r\n    );\r\n  }\r\n});<\/code><\/pre>\n

    Container Components<\/h4>\n

    Container Components are almost always the parents of Presentational Components. In a way, they serve as a intermediary between Presentational Components and the rest of the application. They\u2019re also called \u201csmart\u201d components because they\u2019re aware of the application as a whole.<\/p>\n

    Since Container and Presentational Components need to have different names, we\u2019ll call this one UserListContainer<\/code> to avoid confusion:<\/p>\n

    var React = require('react');\r\nvar axios = require('axios');\r\nvar UserList = require('..\/views\/list-user');\r\n\r\nvar UserListContainer = React.createClass({\r\n  getInitialState: function() {\r\n    return {\r\n      users: []\r\n    }\r\n  },\r\n\r\n  componentDidMount: function() {\r\n    var _this = this;\r\n    axios.get('\/path\/to\/user-api').then(function(response) {\r\n      _this.setState({users: response.data})\r\n    });\r\n  },\r\n\r\n  render: function() {\r\n    return (<UserList users={this.state.users} \/>);\r\n  }\r\n});\r\n\r\nmodule.exports = UserListContainer;<\/code><\/pre>\n

    For brevity, these examples have been leaving out require()<\/code> and module.exports<\/code> statements. But in this case, it\u2019s important to show that Container Components pull in their respective Presentational Components as a direct dependency. For completeness, this example shows all the requires which would be necessary.<\/p>\n

    Container Components can be created just like any other React component. They also have a render<\/code> methods just like any other component, they just don\u2019t create anything to render themselves. Instead, they return the result of the Presentational Component.<\/p>\n

    A quick note on ES6 Arrow Functions:<\/strong> You may notice the classic var _this = this<\/code> trick needed for the example above. ES6 Arrow functions<\/a>, besides having shorter syntax, have other benefits<\/a> which alleviate the need for this trick. To allow you to focus on just learning React, this tutorial avoids ES6 syntax in favor of the older ES5 syntax. However, the GitHub guide for this series makes heavy use of ES6 and it has some explanations in its README files.<\/p>\n

    Events<\/h3>\n

    So far, we\u2019ve shown how state can be passed from Container to Presentational Components, but what about behavior? Events fall into the category of behavior and they oftentimes need to mutate data. Events in React are attached at the view level. For separation of concerns, this can cause a problem in our Presentational Components if we create event functions where the view is.<\/p>\n

    To elaborate, let\u2019s start by adding an event to our Presentational Component (a <button><\/code> you can click) directly to identify problems:<\/p>\n

    \/\/ Presentational Component\r\nvar UserList = React.createClass({\r\n  render: function() {\r\n    return (\r\n      <ul className=\"user-list\">\r\n        {this.props.users.map(function(user) {\r\n\r\n          return (\r\n            <li key={user.id}>\r\n              <Link to=\"{'\/users\/' + user.id}\">{user.name}<\/Link>\r\n              <button onClick={this.toggleActive}>Toggle Active<\/button>\r\n            <\/li>\r\n          );\r\n\r\n        })}\r\n      <\/ul>\r\n    );\r\n  },\r\n\r\n  toggleActive: function() {\r\n    \/\/ We shouldn't be changing state in presentational components :(\r\n  }\r\n});<\/code><\/pre>\n

    This would technically work, but it\u2019s not a good idea. Chances are, the event is going to need to change data, and data which changes should be stored as state \u2014 something the Presentational Component should not be aware of.<\/p>\n

    In our example, the state change would be the user\u2019s \u201cactiveness\u201d, but you can make up any functions you want to tie to onClick<\/code>.<\/p>\n

    A better solution is to pass functionality from the Container Component into the Presentational Component as a prop like this:<\/p>\n

    \/\/ Container Component\r\nvar UserListContainer = React.createClass({\r\n  ...\r\n  render: function() {\r\n    return (<UserList users={this.state.users} toggleActive={this.toggleActive} \/>);\r\n  },\r\n\r\n  toggleActive: function() {\r\n    \/\/ We should change state in container components :)\r\n  }\r\n});\r\n\r\n\/\/ Presentational Component\r\nvar UserList = React.createClass({\r\n  render: function() {\r\n    return (\r\n      <ul className=\"user-list\">\r\n      {this.props.users.map(function(user) {\r\n\r\n        return (\r\n          <li key={user.id}>\r\n            <Link to=\"{'\/users\/' + user.id}\">{user.name}<\/Link>\r\n            <button onClick={this.props.toggleActive}>Toggle Active<\/button>\r\n          <\/li>\r\n        );\r\n\r\n      })}\r\n      <\/ul>\r\n    );\r\n  }\r\n});<\/code><\/pre>\n

    The onClick<\/code> attribute is required to be where the view is \u2014 at the Presentational Component. However, the function it calls has been moved to the parent Container Component. This is better because the Container Component deals with state.<\/p>\n

    If the parent function happens to change the state, then the state change will cause a re-render on the parent function which in turn will update the child component. This happens automatically in React.<\/p>\n

    Here is a demo which shows how the event on the Container Component can change state which will automatically update the Presentational Component:<\/p>\n

    See the Pen React Container Component Demo<\/a> by Brad Westfall (@bradwestfall<\/a>) on CodePen<\/a>.<\/p>\n

    Take note of how this example deals with immutable data<\/a> and makes use of the .bind()<\/a> method<\/p>\n

    Using Container Components with the Router<\/h3>\n

    The router should no longer use UserList<\/code> directly. Instead, it will use UserListContainer<\/code> directly, which in turn will use UserList<\/code>. Ultimately, UserListContainer<\/code> returns the result of UserList<\/code>, so the router will still receive what it needs.<\/p>\n

    Data Flow and the Spread Operator<\/h3>\n

    In React, the concept of props being passed from parent components down to child components is called flow. The examples so far have only shown simple parent-child relationships, but in a real application there could be many nested components. Imagine data flowing from high-level parent components down through many child components via state and props. This is a fundamental concept in React and is important to keep in mind as we move forward into the next tutorial on Redux.<\/p>\n

    ES6 has a new spread operator<\/a> which is very useful. React has adopted a similar syntax<\/a> to JSX. This really helps React with how data flows via props. The GitHub guide for this tutorial uses it too, so be sure to read the guide documentation<\/a> on this feature.<\/p>\n

    Stateless Functional Components<\/h3>\n

    As of React 0.14 (released in late 2015), there is a new feature for creating stateless (Presentational) components even easier. The new feature is called Stateless Functional Components<\/a><\/p>\n

    By now you\u2019ve probably noticed that as you separate your Container and Presentational Components, many of your Presentational ones just have a render method. In these cases, React now allows the component to be written as a single function:<\/p>\n

    \/\/ The older, more verbose way\r\nvar Component = React.createClass({\r\n\r\n  render: function() {\r\n    return (\r\n      <div>{this.props.foo}<\/div>\r\n    );\r\n  }\r\n\r\n});\r\n\r\n\/\/ The newer \"Stateless Functional Component\" way\r\nvar Component = function(props) {\r\n  return (\r\n    <div>{props.foo}<\/div>\r\n  );\r\n};<\/code><\/pre>\n

    You can clearly see that the new way is more compact. But remember, this is only an option for components that just need a render<\/code> method.<\/p>\n

    With the new Stateless Functional way, the function accepts an argument for props<\/code>. This means it doesn\u2019t need to use this<\/code> to access props.<\/p>\n

    Here is a very good Egghead.io video<\/a> on Stateless Functional Components.<\/p>\n

    MVC<\/h3>\n

    As you\u2019ve probably seen so far, React doesn\u2019t resemble traditional MVC. Often times React is referred to as \u201cjust the view layer\u201d. The problem I have with this statement is that it\u2019s too easy for React beginners to believe that React should<\/em> fit into their familiarity with traditional MVC, as if it\u2019s meant to to be used with traditional controllers and models brought in from third-party.<\/p>\n

    While it is true<\/em> that React doesn\u2019t have \u201ctraditional controllers\u201d, it does provide a means to separate views and behavior in its own special way. I believe that Container Components serve the same fundamental purpose that a controller would serve in traditional MVC.<\/p>\n

    As for models, I\u2019ve seen people use Backbone models with React and I\u2019m sure they have all kinds of opinions on whether that worked out well for them. But I\u2019m not convinced that traditional models are the way to go in
    \nReact. React wants to flow data in a way that just doesn\u2019t lend itself well to how traditional models work. The Flux design pattern,
    created by Facebook<\/a>, is a way to embrace React\u2019s innate ability to flow data. In the next tutorial, we\u2019ll cover Redux, a very popular Flux implementation and what I view as an alternative to traditional models.<\/p>\n

    Summary<\/h3>\n

    Container Components are more of a concept and not an exact solution. The examples in this tutorial just are one way to do them. The concept though, is so well accepted that it\u2019s even Facebook\u2019s policy<\/a> to use them within their teams — although they might use different terminology.<\/p>\n

    This tutorial was highly influenced by other<\/a> articles<\/a> on this topic. Be sure to look at this tutorial\u2019s official GitHub guides<\/a> for even more information and a working example of Container Components.<\/p>\n


    \n
    \n

    Article Series:<\/h4>\n
      \n
    1. React Router<\/a><\/li>\n
    2. Container Components (You are here!)<\/strong><\/li>\n
    3. Redux<\/a><\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"

      This tutorial is the second of a three-part series on React by Brad Westfall. This series is all about going beyond basic React skills and building bigger things, like entire Single Page Applications (SPAs). This article picks up where the last article, on React Router, left off.<\/p>\n","protected":false},"author":230276,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[648,647,557],"jetpack_publicize_connections":[],"acf":[],"jetpack_featured_media_url":"","jetpack-related-posts":[],"featured_media_src_url":null,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/239591"}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/230276"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=239591"}],"version-history":[{"count":10,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/239591\/revisions"}],"predecessor-version":[{"id":253648,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/239591\/revisions\/253648"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=239591"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=239591"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=239591"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}