In the React <Fetch> example, the first clause matches props against the pattern ({ loading }):
<Fetch url={API_URL}>
{props => match (props) {
when ({ loading }) { <Loading />; }
when ({ error }) { <Error error={error} />; }
when ({ data }) { <Page data={data} />; }
}}
</Fetch>
If the <Fetch> component is react-fetch-component, then props.loading will be true, false, or null. Does loading need to be truthy to match? If not, the clause will _always_ match and never consider the subsequent clauses.
The example could be instead written as:
match (props) {
- when ({ loading }) { <Loading />; }
+ when ({ loading }) if (loading === true) { <Loading />; }
when ({ error }) { <Error error={error} />; }
when ({ data }) { <Page data={data} />; }
}
...or more succinctly:
match (props) {
- when ({ loading }) { <Loading />; }
+ when ({ loading: true }) { <Loading />; }
when ({ error }) { <Error error={error} />; }
when ({ data }) { <Page data={data} />; }
}
But what happens in the second clause? What objects does the pattern ({ error }) _not_ match? Does it match { error: undefined }? Does it do an Object.hasOwnProperty check (which would rule out matching properties on classes, such as Response.prototype.status)?
The example could be rewritten unambiguously, but it is not ideal:
match (props) {
- when ({ loading }) { <Loading />; }
+ when ({ loading: true }) { <Loading />; }
- when ({ error }) { <Error error={error} />; }
+ when ({ error }) if (error !== undefined) { <Error error={error} />; }
when ({ data }) { <Page data={data} />; }
}
There should be no assumption that <Fetch> in the example is any particular library, and thus there should be no assumption about the possible types of properties on props.
The first clause matches when loading is present. The second matches when error is present. The third matches when data is present. The example is meant to imply that _this_ Fetch provides one of those three untagged unions when calling the render prop.
Perhaps it would be clearer if we provided an example Fetch component so the difference is clear?
How does it work with tagged union?
match (x) {
when ({ type: "A", ...rest }) -> expr
when ({ type: "B", ...rest }) -> expr
}
Does it work in this way?
@Jack-Works yep! In the case of a B type, the first match would fail, and the second would succeed.
How much does it really matter? It seems to me an old example, since rendering props is hardly used today, I believe that pattern matching will end up being more used internally in API's like react-query that uses hooks, which are more adopted today
Hooks don't really replace the need of rendering props - they're mostly to help replace the need of lifecycle hooks. - I think that example is still a relevant example, as I still write React code that way.
Even though hooks were to replace the default lifecycle, render props worked much better on class components, well since hooks were released I've never seen a useful application for rendering props, but I understand
Most helpful comment
Hooks don't really replace the need of rendering props - they're mostly to help replace the need of lifecycle hooks. - I think that example is still a relevant example, as I still write React code that way.