Simple React Patterns
lucasmreis.github.io
lucasmreis.github.io
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.
[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...
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.
I've thought it's just technically impossible (no API to do so) to cancel a `fetch` request in progress.
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).
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 })) this.cancelOnUnmoun(new Promise(...)).then(...)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).
The React lifecycle has `componentDidMount` for doing stuff (at most once) after rendering.
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.
componentDidMount() {
if (!this.unmounted) ...
}
componentWillUnmount() {
this.unmounted = true
}- 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.)
const PlanetView = ({planet}) => <div>{planet ? planet.stuff : 'Loading...'}</div>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!
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)
Will be good to correct that since it's pretty confusing.
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.
1: https://github.com/acdlite/recompose
2: https://github.com/acdlite/recompose/blob/8c4ac2e4/docs/API....
https://github.com/acdlite/recompose/blob/8c4ac2e4a4cd8d60c8...
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.
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.
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.
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.
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.
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.
What do you think of citrus so far? Is it production ready? Stable? Anything missing?
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.)
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 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).
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 })
);
} .then(
planet => this.setState({ loading: false, planet }),
error => this.setState({ loading: false, error })
); 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. 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 occuredThat function is thenable so following it .then is called and the result or error is passed to the first or second function respectively.
// 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)
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".
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?