This is a feature request.
The current hooks API provides everything that is necessary to create sophisticated and elegant applications. However, the current api is something of a step backwards in terms of scannability - e.g. Understanding when various code will execute in the component's lifecycle.
As a trivial example, suppose I simply want to log some information everytime a component unmounts for some analytics purpose. That's it. Right now, the simple implementation is:
useEffect(() => {
return () => {
fetch('some-analytics-api.com');
}
}, [])
There's no issue with whether this code works. Clearly it does. However, when developers are scanning the code base littered with multiple useEffect invocations, all of which have different memoization arrays, it takes a second to realize what this code is supposed to be doing - "Hmm, I see we're sending some analytics request. Okay, it's a callback returning a callback, so it's a disposer function. Oh, and there's an empty array as the final parameter, so the disposer only fires when the component unmounts". That fraction of a second to make that determination is just a bit too long in my opinion. With a new topLevel API useUnmount it is grokkable almost instantly:
useUnmount(() => {
fetch('some-analytics-api.com');
})
This proposal is to add a set of top level primitives that map more directly to the API's that developers are already familiar with and that correspond more closely to the lifecycle events developers think about when reasoning about application flow. The proposed top level hooks include useMount, useUnmount with either an optional flag to run inside a layout effect, or else two additional top level hooks useLayoutMount, useLayoutUnmount.
A likely concern with this proposal is that it will unnecessarily bloat the top level API. The reasoning goes: Why add to the top level API convenience wrappers that can be coded in userland? It's a legitimate concern. In this case however, I argue that the use case is so common that the benefits outweigh the cost. To borrow an analogy, developers have been able to perform Array.map since the invention of Javascript, but once it's usefulness and ubiquity was established, it was added to the language proper. I'm making this same argument for useMount and useUnmount.
As evidence that these convenience wrappers are going to become extremely popular, simple Github searches for uses of useUnmount and useMount (https://github.com/search?q=useUnmount+react&type=Code and https://github.com/search?q=useMount+react&type=Code) return some 100+ repos already declaring their own convenience wrappers for these effects. Unless added to core, this number will expand drastically once hooks leave alpha. Clearly developers want these convenience wrappers, and will either write them themselves or import an external library (lodash for React? Please no...) that does it for them.
Another likely concern with this proposal is that developers will use these syntactic sugar functions to write less optimized and self contained code. To borrow an example from the documentation, the fear is that instead of:
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, []);
Devs will inefficiently do:
useMount(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
})
useUnmount(() => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
})
From a practical performance perspective though, these two implementations are basically identical and not worth worrying about. Function definitions and invocations are cheap in modern javascript. As to the issue of the code being less self contained, in most instances I believe that won't be a problem since developers will simply extract the logic into a self contained custom hook like useFriendStatus that encapsulates all the logic into an atomic piece.
One small additional benefit: With useMount/useUnmount being in React Core, instead of dozens of different snowflake implementations, there may feasibly be future optimizations on the hooks that React core will then be able implement on an ecosystem wide basis.
So in summary, it seems to me that React can either fight the inevitable or embrace it.
As a purely stylistic (for now at least) question, there's no real right or wrong answer to this proposal and barring extremely strong technical reasons against the proposal, I'm not sure how it can be discussed cooly and objectively. Maybe a developer survey?
This is a feature request.
The current hooks API provides everything that is necessary to create sophisticated and elegant applications. However, the current api is something of a step backwards in terms of scannability - e.g. Understanding when various code will execute in the component's lifecycle.
As a trivial example, suppose I simply want to log some information everytime a component unmounts for some analytics purpose. That's it. Right now, the simple implementation is:
There's no issue with whether this code works. Clearly it does. However, when developers are scanning the code base littered with multiple
useEffectinvocations, all of which have different memoization arrays, it takes a second to realize what this code is supposed to be doing - "Hmm, I see we're sending some analytics request. Okay, it's a callback returning a callback, so it's a disposer function. Oh, and there's an empty array as the final parameter, so the disposer only fires when the component unmounts". That fraction of a second to make that determination is just a bit too long in my opinion. With a new topLevel APIuseUnmountit is grokkable almost instantly:This proposal is to add a set of top level primitives that map more directly to the API's that developers are already familiar with and that correspond more closely to the lifecycle events developers think about when reasoning about application flow. The proposed top level hooks include
useMount,useUnmountwith either an optional flag to run inside a layout effect, or else two additional top level hooksuseLayoutMount,useLayoutUnmount.A likely concern with this proposal is that it will unnecessarily bloat the top level API. The reasoning goes: Why add to the top level API convenience wrappers that can be coded in userland? It's a legitimate concern. In this case however, I argue that the use case is so common that the benefits outweigh the cost. To borrow an analogy, developers have been able to perform
Array.mapsince the invention of Javascript, but once it's usefulness and ubiquity was established, it was added to the language proper. I'm making this same argument foruseMountanduseUnmount.As evidence that these convenience wrappers are going to become extremely popular, simple Github searches for uses of
useUnmountanduseMount(https://github.com/search?q=useUnmount+react&type=Code and https://github.com/search?q=useMount+react&type=Code) return some 100+ repos already declaring their own convenience wrappers for these effects. Unless added to core, this number will expand drastically once hooks leave alpha. Clearly developers want these convenience wrappers, and will either write them themselves or import an external library (lodash for React? Please no...) that does it for them.Another likely concern with this proposal is that developers will use these syntactic sugar functions to write less optimized and self contained code. To borrow an example from the documentation, the fear is that instead of:
Devs will inefficiently do:
From a practical performance perspective though, these two implementations are basically identical and not worth worrying about. Function definitions and invocations are cheap in modern javascript. As to the issue of the code being less self contained, in most instances I believe that won't be a problem since developers will simply extract the logic into a self contained custom hook like
useFriendStatusthat encapsulates all the logic into an atomic piece.One small additional benefit: With
useMount/useUnmountbeing in React Core, instead of dozens of different snowflake implementations, there may feasibly be future optimizations on the hooks that React core will then be able implement on an ecosystem wide basis.So in summary, it seems to me that React can either fight the inevitable or embrace it.
As a purely stylistic (for now at least) question, there's no real right or wrong answer to this proposal and barring extremely strong technical reasons against the proposal, I'm not sure how it can be discussed cooly and objectively. Maybe a developer survey?