Hacker News new | comments | show | ask | jobs | submit login
Simple React Patterns (lucasmreis.github.io)
625 points by kawera 74 days ago | hide | past | web | favorite | 83 comments



This is an _excellent_ summary of some of the most useful React patterns. I can also recommend "React Patterns" [0] and "React Bits" [1], which show a variety of other useful patterns as well.

Beyond those, my React/Redux links list has sections on "React Component Patterns" [2] and "React Component Composition" [3], with links to many additional articles on these topics.

[0] http://reactpatterns.com/

[1] https://github.com/vasanthk/react-bits

[2] https://github.com/markerikson/react-redux-links/blob/master...

[3] https://github.com/markerikson/react-redux-links/blob/master...


The problem with resolving promises inside of `componentDidMount` is that there is no way to cancel those promises. If the component is unmounted, and then setState is called, it will generate an error (or a warning. I can't remember).

Facebook discusses this on its blog: https://reactjs.org/blog/2015/12/16/ismounted-antipattern.ht...

I've been using Observables which, in my experience, bind a little cleaner than Promises to React components.


Yes there was a whole discussion in a github issue about the correct pattern to solve this. Creating and guarding against a `isMounted` field in your `.then()` callbacks means you prevent garbage collection of the unmounted components. An easy solution is to use cancellable promises (with some subtleties to allow garbage collection). There's an implementation which take care of this properly here (provides an HoC): https://github.com/hjylewis/trashable-react .


When you say "cancellable promises", that means that you cannot use native JS promises, correct?


You can, you just need to wrap it when used inside a react component.


How?

I've thought it's just technically impossible (no API to do so) to cancel a `fetch` request in progress.


We're talking about several different things:

Native promises do not have a "real" cancellation API (no 3rd path besides resolved and rejected) but you can mimic the functionality by rejecting with a dedicated error type, or use another promise as a cancellation token for example.

fetch(), which uses promises as return type, do not support aborting requests, as discussed [here](https://github.com/whatwg/fetch/issues/447) but the [old XMLHttpRequest does](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequ...).

Aborting is specific to HTTP requests, it's stopping the connection to the remote server (so technically impossible to implement with the current APIs as you said). Cancelling a promise is just stopping all onResolved continuations to be called, so it can be implemented in several different ways as I explained above.

The end result if you use a classic cancellation wrapper on a fetch() promise is that the onReject continuations will be called immediately with a specific reason. The HTTP request will continue to the end (no abort), but the response will be ignored.

In the case of the react library I mentioned, both the onResolved and onReject continuations will be ignored if cancelled, it's the subtlety that allows the component to be garbage collected (and probably why the author decided to call that "thrashable" as opposed to "cancellable" to mark the difference).


For example, you can wrap a promise such that when it finally resolves, it checks an isCancelled flag and rejects instead so that your .then callbacks aren't run.

It's not about cancelling any potential inflight action within the promise itself.

In this case, you don't want the callback to run after the react component unmounts, nor do you want to hold a reference to the component:

    promise
        .then(value => this.setState({ value }))


You don't have to cancel the fetch request, you just have to cancel its callback.


Promises? Cancellation? The whole point of a Promise is that it must resolve to something eventually.


You're cancelling the promise from the perspective of the caller, not the Promise itself. Promises themselves can't decide that they don't want to resolve, but there's plenty of cases where whoever requested the promise in the first place is no longer interested in the results.


Where is the typical place to put initial fetches? I've been setting empty state and then calling a method at the end of a constructor which ultimately results in a promise that calls setState with the data.

But I would never do something like that in, say, the constructor of a WPF/UWP windows app as those have "Loaded" or "Loading" events of some kind (which is parallel to componentDidMount).


`componentDidMount`, which is after a React component has been rendered. This contradicts the parent commenter directly but I'm fine with that.

The React lifecycle has `componentDidMount` for doing stuff (at most once) after rendering.


I don't understand what you're saying.

Once the component mounts, then it can be unmounted. The upstream comment is talking about when you have a promise that is still running after unmount.


In Android (for example), one would use an observable stream bound to the lifecycle of the host. Most folks do this using Rx and add a custom operator for unsubscribing on the host DESTROY event.


Protect the setStates in the callback with a conditional switch that gets flipped off in componentWillUnmount.


Not clear on what you're saying, pseudocode?


In componentWillUnmount, set a var componentUnmounted true. In componentDidMount in the callback for the fetch, check for componentUnmounted before setting state for an error or whatever you want to do.


Set a variable... set a property in the component state? Or set a static variable on the class?


I use a static var on the class.

  componentDidMount() {
   if (!this.unmounted) ...
  }

  componentWillUnmount() {
   this.unmounted = true
  }


That's not a static car on the class. It's on the instance! A static class property would entail something like `Foo.unmounted = true` (a bad idea).


it would be nice if React.Component had a cancel method, so you could simply drop all your promises into it and they get canceled when the component unmounts.

    this.cancelOnUnmoun(new Promise(...)).then(...)


Two things I don't like about the approach taken with these specific examples (and they're related):

- It's harder to see the structure of a page when the parts are composed functionally instead of structurally (i.e. explicit nesting); but functional composition is required because the next step down from components are DOM elements

- This approach makes consistent styling of a large application difficult because it ties business domain views to low-level details like specific DOM elements

(I don't disagree with the patterns themselves, per se. But I wouldn't make them domain specific.)

I'd prefer to code up pages using components designed around a higher level of abstraction: more like UI widgets, and less like business domain specific views. That gives two benefits: increased consistency because there are fewer ways to compose higher level abstractions for a given screen complexity; and it's possible to use nesting more directly, since the nesting won't be so verbose, because the raw materials are higher level abstractions than <span> and <div>, they're more like <DropdownMenu> and <MenuItem>.

(This approach is what we do where I work, only it's been built out of Backbone because that was what was current at the time. It's basically MVVM where the viewmodel is the model for a UI component, rather than anything in the domain of the business. An early anti-pattern in Backbone was to have one-off views for every individual little bit of the page; we found this to make understanding the whole composition very awkward.)


CSS-in-JS libs like https://emotion.sh make "micro-componentization" even easier - pretty much every raw DOM element can be replaced by a domain-relevant/ui-relevant component type. Then if you need to add something beyond styles like state or complex render logic, the consumers don't even know about it because the reference is the same.


That ~30 line component should be reduced to something resembling this:

  const PlanetView = ({planet}) => <div>{planet ? planet.stuff : 'Loading...'}</div>


It's demonstrating a component that needs I/O, so I'm not sure how refactoring it into one that needs its parent to do the I/O helps the demonstration.


After 2+ years of writing React most of the day every day with a lot of different patterns coming in and falling out of love in our app, our experience falls almost exactly in line with this. It's simpler than I would have imagined from when we first started using React/Redux and handles the most complex interfaces our app has.

My favorite part is how he models the different states the component can have. He describes the different states in a comment block but we found it even nicer to use Flow and disjoint unions to help the developer avoid impossible states which we learned from a talk by Jared Forsyth: https://www.youtube.com/watch?v=V1po0BT7kac. Another huge boon in productivity and so simple and obvious in hindsight!


> He describes the different states in a comment block but we found it even nicer to use Flow and disjoint unions to help the developer avoid impossible states

I'm on the highway to Elm <insert music note because HN hates unicode>

(or reason, or purescript, either way towards a language with first-class sum types support, that's just so convenient)


The author claims the article [1] says render props are anti-pattern, while this is not true. The only thing that's called an anti-pattern there is "children as a function". If you use properly named render prop other than children, they seem to be fine with that.

Will be good to correct that since it's pretty confusing.

[1] http://americanexpress.io/faccs-are-an-antipattern/


How does the pervasive use of higher-order functions affect debugging?

Take this example:

  const withDagobah = ({
    LoadingViewComponent,
    ErrorViewComponent,
    PlanetViewComponent
  }) =>
    class extends React.Component {
      …
    };
In a language with proper generics, you’d write this instead:

  class Dagobah<LoadingViewComponent, ErrorViewComponent, PlanetViewComponent> extends React.Component {
    …
  }
And then you’d clearly have an object of type Dagobah<LoadingView, ErrorView, PlanetView>, easy to inspect and debug. (And Dagobah<A, B, C> = Dagobah<A, B, C>, whereas withDagobah(A, B, C) ≠ withDagobah(A, B, C).)

(I’ll ignore the topic of type erasure.)


If you inspect the component tree using the React DevTools, you'll be able to see exactly what values each component is passing to its children, and what their internal state is. So, use of HOCs adds an extra level of nesting to the component tree, but it should also be very clear in there what each component is passing down.


Part of me is sad that Javascript has now been made OOP, after a majority of efforts pushing the balance towards becoming more and more functional (e.g. PureScript) only a few years ago.


React explicitly discourages using inheritance with components, instead promoting composing components together like functions. You're also encouraged to keep them stateless if possible, so they create the same output for the same input. I'll need some convincing that functional programming is on its way out in JavaScript.


Yeah, but why did they switch from `React.createClass({..})` to the class syntax? Classes are terrible in JS, they're not even native JS, it doesn't fit in JS. This change alone has brought more and more OO JS code.


Prior to ES6, there were hundreds of incompatible class-like implementations in the JS ecosystem, and every major library had its own. That included React.

Now that ES6 classes are actually part of the language, there's no reason for the React team to continue maintaining their own class-like implementation. They can defer that to the language itself. This also enables better use of standardizing tooling around the JS language.


I thought `createClass` does/did something essentially similar to what `class` does in ES6. Not having to use a framework's custom class-creation machinery doesn't seem like a big loss to me or like it is has anything to do with functional programming.


Yep. It also had some differences in behavior. `createClass` auto-bound functions so that `this` always pointed to the component instance, and it supported mixins.

The React team now encourages functional forms of composition rather than use of mixins, so that's another reason why React.Component doesn't support them. The lack of automatic method binding has certainly been a major pain for people learning and using React, but it also means that there's no "magic" involved. The Stage 3 Class Properties syntax is the recommended way to ensure that methods are bound properly, and there's plenty of other possible solutions as well.


Classes in JS6 are just a syntax sugar for the native JS prototype inheritance.

Nothing "terrible", absolutely native (both since the keyword is part of JS and since the implementation is based on prototypes that have been with JS since the beginning), and fits perfectly.


In React v0.13 https://reactjs.org/blog/2015/03/10/react-v0.13.html, they claimed the reason for the switch is because the `class` syntax is for "more flexibility." What can you do with the `class` syntax that you can't do with the functional syntax? Furthermore, you can generate React code much easier with the functional syntax than with the class syntax.

Also, the functional syntax has mixins and other ways to combine objects or share code, I think that would be harder to do with classes, which make them even less flexible.


Seems like a weird thing to miss for someone who ostensibly prefers functional programming.

For example, people here will talk about `function User() {}` like it's the pinnacle of amazing abstraction. Because it has the word "function" in it or something.

There's nothing functional about that to me. Mutating the prototype and dealing with the implicit `this` variable in your functions is about as far away from functional programming as you can get.

Meanwhile Javascript just gets more and more functional, from the mindshare of higher order functions/components gaining traction to the @decorator transformation to the Promise 'monad'. It just gets better and better.

I have a hard time taking anyone seriously who doesn't recognize the pain that `class` solved in the ecosystem whether you personally decide to use it or not. People have been writing OOP code in Javascript since day one, just with some of the worst idiosyncrasies of all OOP languages.


People also write tons of bad functional code with JS. It gets worse and worse the more that people keep following this cargo cult of HOCs and functional programming. The obsession with using HOCs for passing a simple variable around is particularly absurd. Importing objects with methods (or even just a namespace with functions) is way, way cleaner than importing every function seperately.

Which stable and widely used GUI kit has ever been done well with functional programming? Until one exists, I can’t really take anybody who pushes functional programming for GUIs very seriously.

Functional programming just isn’t that good for complex domains. OOP is way better for GUIs.


ReasonML and ReasonReact agree with you: instead of HOCs, they prefer using standard functions, explicit “self”, and just passing things down through props. It’s quite a breath of fresh air really.


I suppose it isn't really a GUI but it does manage them.

http://xmonad.org/


At the moment, React does not yet have support for stateful functional components. It's something they've said they would _like_ to research and implement down the road, but right now, component state and lifecycle methods requires class components.


Or the use of something like recompose[1]'s `lifecycle` function[2].

1: https://github.com/acdlite/recompose

2: https://github.com/acdlite/recompose/blob/8c4ac2e4/docs/API....


Yeah, although that itself is implemented internally using an ES6 class:

https://github.com/acdlite/recompose/blob/8c4ac2e4a4cd8d60c8...


What do you mean native JS? It doesn't get much more native than "given keywords and syntax in the language and in the specification"


Classes are perfectly fine in JS, they are just syntactic enhancements for managing prototypes more easily.


Not sure what you mean by 'just syntactic enhancements'. Check this out https://esdiscuss.org/topic/javascript-vision-thing#content-...


ClojureScript's re-frame[0] is my favorite way to React, honestly. PureScript's halogen is also pretty nice. Re-frame has a built-in, functionally pure way to do ajax and side-effects, too, which comes in pretty handy.

[0] https://github.com/Day8/re-frame


I use reframes little brother, citrus with cljs and it has been awesome. The promise of data oriented frontend engineering really pays off.

https://github.com/roman01la/citrus


Awesome! I've used reagent/re-frame extensively for years, but I've never tried Rum because I couldn't find an obvious way to use it with re-frame.

What do you think of citrus so far? Is it production ready? Stable? Anything missing?


actually once redux is introduced to react it's very very very functional.. so hold the sadness


React is functional even without Redux :-)

Look at the Reason team, with their Reason-React implementation. Cheng Lou seems to actively dislike a single store that Redux is, and, if anything, co-locates stores to stateful components.


That sounds more like flux, how do they avoid all the boilerplate that flux was? It was very very painful.


I am always intrigued when I come across an article like this, after having done 2+ years of React development, and have never seen these patterns (Provider Pattern), nor seen them debated (Render Props). I do pay attention to the community here and there, and constantly poke around open source react libraries.

I tend to bring in patterns from iOS development, such as Delegates, especially when using React Native, and is really useful when using Flow or TypeScript.

We heavily rely on the Material-UI library (https://material-ui-next.com/) and have brought a lot of their patterns into our libraries, mostly how reusable components are composed.


I just heard about the Provider pattern this week when reading about using react-router and mobx. That being said, it is a solution to a "problem" that I noticed fairly early on in my react usage.


The Container/View Pattern in this article, isn't this MVC?


You could argue it's a variation thereof, more like MVVC (Model View ViewController) maybe. In React you only really have the View layer. In this case, there's two views, a 'functional' view (the ViewController) and the 'presentation' view (the View itself).

I guess the main difference is that in MVC, the view and controller are two separated entities (side-by-side), while in React it's embedded (Controller wraps around View).


I'm new to React. From what I read, isn't React only the View? I thought its structure was more like pure view layers glued by light logic to form a higher level view. It seems I was wrong now.


Your explanation nails it. Thank you for clarifying!


This part seems strange. What is it supposed to do?

    componentDidMount() {
     fetch("https://swapi.co/api/planets/5")
      .then(res => res.json())
      .then(
       planet => this.setState({ loading: false, planet }),
       error => this.setState({ loading: false, error })
      );
    }


When the component is mounted on the page, a planet is fetched from an api. Then the response body is parsed to JSON. After that the object is added to the component state. When there was an error it is added to the state instead.


    Then the response body is parsed to JSON
The "res => res.json()" call? But what does this do? res seems to be used nowhere and just discarded without any side effects.


If it's a simple statement of this form, the result of the expression is returned.

so res => res.json() is just like having a callback like:

function(res) { return res.json() }

and the next part in the then() chain, takes that result as "planet".

Basically, that last part of the chain, has a signature like:

(function callback(...), function errorCallback(...))

and the callback part gets the result of the previous step as "planet" (if all went ok). If there was an error in the previous steps of the chain, the errorCallback would get called, with the exception passed in as "error".


If it makes it easier to reason about, it's equivalent to:

    // The Promise resolves when the server starts responding
    const response = await fetch(…);
    
    // The Promise resolves when both the transfer and the JSON parsing ended
    const body = await response.json();
So, yes, `response` is only used once and then discarded.

`fetch()` may fool you into thinking that it resolves when the request is complete, but it's always a 2-step operation (unless you start implementing a streaming interface, then it's more than 2 steps)


Ah! The equivalent with await seems much clearer to me.


This is a shorthand for

    function (r) { return r.json()}
Note the extra return. We return the JSON decoded response that is our planet. and use its value to set state if no error occured


Got it! Thanks!


This is pretty straightforward es6. The difference between =>{} and just => is confusing at first. One is a function body and the other is an implied return statement.


`res.json()` is the return value of the first `then` block, which is then passed to the second `then` block as `planet` (if json parsing doesn't throw an error).


res => res.json() returns the result of res.json()

That function is thenable so following it .then is called and the result or error is passed to the first or second function respectively.


It fetches data from an endpoint then sets component state based on the response


Well, it makes a http request but it seems to do nothing with the data returned.


The data is set as component state

  .then(
        planet => this.setState({ loading: false, planet }),
        error => this.setState({ loading: false, error })
       );


Fetching data directly in components is bad advice and leads to a program with cluttered data access becoming more and more unmaintainable as the app grows. You need to encapsulate fetching and storage in redux or a similar state management solution.


Correct me if I'm wrong, but these patterns don't seem very much like a Redux way to do things. A lot of things feel somewhat implicit too. For example, I stopped just spreading my state into the child component, opting to be explicit nearing verbose instead.


While I'm not sure it's a 'Redux thing', I've also become more conservative in my 'spreading'. I'm not necessarily against it, but too often the resulting code started feeling too alien and dense. The former is bad for working with people new to ES2015+, but the latter started bothering me even in my own projects.


this is awesome, so easy to understand. looking forward to more!


His example:

    const withDagobah = PlanetViewComponent =>
      class extends React.Component {
        ...
      }
    }
Seems as if it would be pretty bad from a perf perspective. It's defining a class every time that function is called. Anyone familiar with the dark underside of JavaScript care to comment?


A class is just a constructor function (in this case the function is a React component), so it is a function returning a function, which is a fairly common activity.


It's evaluated once at script parsing/evaluation time so it's not really expensive.


It is only going to be called once (per componented used in) upon loading the page. No biggie




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: