Skip to content

Instantly share code, notes, and snippets.

@chantastic
Last active November 10, 2024 13:39
Show Gist options
  • Save chantastic/fc9e3853464dffdb1e3c to your computer and use it in GitHub Desktop.
Save chantastic/fc9e3853464dffdb1e3c to your computer and use it in GitHub Desktop.
JSX, a year in

Hi Nicholas,

I saw you tweet about JSX yesterday. It seemed like the discussion devolved pretty quickly but I wanted to share our experience over the last year. I understand your concerns. I've made similar remarks about JSX. When we started using it Planning Center, I led the charge to write React without it. I don't imagine I'd have much to say that you haven't considered but, if it's helpful, here's a pattern that changed my opinion:

The idea that "React is the V in MVC" is disingenuous. It's a good pitch but, for many of us, it feels like in invitation to repeat our history of coupled views. In practice, React is the V and the C. Dan Abramov describes the division as Smart and Dumb Components. At our office, we call them stateless and container components (view-controllers if we're Flux). The idea is pretty simple: components can't be concerned with both presentation and data-fetching. I feel like an example might be clearer...

A component like this would be rejected in code review for having both a presentation and data concern:

// CommentList.js
import React from "react";

class CommentList extends React.Component {
  constructor() {
    super();
    this.state = { comments: [] }
  }
  
  componentDidMount() {
    fetch("/my-comments.json")
      .then(res => res.json())
      .then(comments => this.setState({ comments }))
  }
  
  render() {
    return (
      <ul>
        {this.state.comments.map(({ body, author }) =>
          <li>{body}-{author}</li>
        )}
      </ul>
    );
  }
}

It would then be split into two components. The first is like a traditional template, concerned only with presentation, and the second is tasked with fetching data and rendering the related view component.

// CommentList.js
import React from "react";

const Commentlist = comments => (
  <ul>
    {comments.map(({ body, author }) =>
      <li>{body}-{author}</li>
    )}
  </ul>
)
// CommentListContainer.js
import React from "react";
import CommentList from "./CommentList";

class CommentListContainer extends React.Component {
  constructor() {
    super();
    this.state = { comments: [] }
  }
  
  componentDidMount() {
    fetch("/my-comments.json")
      .then(res => res.json())
      .then(comments => this.setState({ comments }))
  }
  
  render() {
    return <CommentList comments={this.state.comments} />;
  }
}

In the updated example, CommentListContainer could shed JSX pretty simply.

  render() {
    return React.createElement(CommentList, { comments: this.state.comments });
  }

Additionally, a Higher-order Component or component with Render Props could help in making container components and stateless components more composeable

What does this have to do with disliking JSX?

When we started doing this, concerns about JSX vanished. Writing "dumb components" feels just the same as Handlebars or ERB templates but with the full power of JavaScript. We realized that it wasn't JSX that bothered us as much as the nagging feeling that components were just smaller balls of mud. For a while, our components were just smaller balls of mud but this pattern helped break the cycle.

I hope that this was a helpful addition to the conversation. I've written about it in slightly more detail here and here. You can also see Jason Bota's talk about how they do this at Facebook.

Cheers!

Michael

Hi Everyone else 👋

You likely got here from a very popular article by Dan Abramov on the topic of container components.

I'm surprised by the ammount of attention this resource has recieved as it's just an extension of a Twitter conversation I was having.

Gists are a terrible medium because I don't get notified on comments. I've taken a little time today to modernize the code example. So it shouldn't look as foreign to newcomers.

If you'd like more up-to-date React recourses, I mantain these sites:

learnreact.com
reactpatterns.com
reactcheatsheet.com

These resources are more closely monitored and updated.

Thanks for the support!

💖 @chantastic

@danny-andrews
Copy link

Rad stuff, dude!

@arshabh
Copy link

arshabh commented Jun 26, 2017

I have a similar issue as @egorovli. I am also create smart components using connect from react-redux. I dont know how i can pass data from server as props to the presentational component directly. I also do something similar to what he is doing. I agree it is not the best approach as its beats the purpose - so what do i do ?

@morenoh149
Copy link

@egorovli @arshabh in my project we promote the redux container to a react component as well. So you end up with two components, one presentational one container, and the container is decorated with redux (mstp, mdtp).

@ozanmuyes
Copy link

Hi @chantastic,

I've just came here from Dan Abramov's Presentational and Container Components article. Thanks for the awesome example.

There is a small thing that I've wanted to add to your example, the key attribute for li element. I, myself, started to learning the React, after reading 'get started' and 'advanced' guides on React's page (especially this one) I stumbled upon the example of yours. I thought, for the first timers like me, it would be really good to see the key points (pun intended) in action.

Regars.

@BeijiYang
Copy link

I came from Dan Abramov's Presentational and Container Components article, too. This brilliant example really helps me a lot. Thank you !

@ldfloresgon
Copy link

hi guys, I am reading Learning React from Alex Banks & Eve Porcello, I recommend this book, it's amazing :), in this book there are a lot of references to Dan Abramov , and sorry for the question, but... when a component doesn't need state, what kind of component are you using? Stateless Component or PureComponent?, and why? I am using Stateless Component. Thanks a lot !!!

@borela
Copy link

borela commented Dec 23, 2017

A decorator to simplify the separation: https://github.com/borela/presentable

@mickeypuri
Copy link

Using Container as a common suffix creates a lot of noise in the code. Have you looked at any other potential shorter suffix? I thought maybe VC for view controller. That said it is nice to try aim for some kind of generic such as Ctrl for controllers in Angular. Just wondering if some such accepted short form exists

@gilador
Copy link

gilador commented Dec 12, 2019

this approach does the trick of separation - A BUG TAHNK YOU! - although I have one comment about it: since the container is a component by definition, nothing is holding from developers to mix concerns and apply presentation-related code in to it

@heytulsiprasad
Copy link

Thank you for sharing your conversation, out in the public! Also to Dan for mentioning this in his blog!

@TheRakeshPurohit
Copy link

Here after honeypot's reactjs documentary.

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