-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Umbrella: New Life-Cycles Ideas #7678
Comments
I'd also like to see |
If you mutated A slightly better API would be something like I'm not too worried about making this case easier since you can already do it, it is possible to avoid completely (ComponentKit has lived without this just fine), and using it has some footguns regardless. |
That said, Fiber currently can call |
I'm specifically interested in a single non-constructor method that gets called before the first render on both client and server, in case that wasn't clear - which do you recommend for that? |
@ljharb |
About I don't really see any use case for About |
The use cases for componentDidServerRender are outlined in the linked issue. As for the WasMounted cases. The user cannot know which is the best scheduling. Neither of those are the best since they would conflict with the next frame rendering and would block React. There is also a significant difference. React still have to do work synchronously to walk a tree and invoke those calls. It may not be the bottleneck right now but that's because we don't have Fiber yet. When we do, it can be the difference between dropping a frame and not. I'm not sure what you mean about the scroll example. What do you mean by "rendering phase"? |
I can't fathom not having a synchronous didMount method. Lots of product code still relies on reading from the DOM to set up the initial view. |
@joshduck The proposal is not to deprecate didMount but to use it less. It is overusing it that is the problem, not the very existence. The primary synchronous use case is reading from layout and rendering again as a result. That said, async layout out of the document is something I hope we'll eventually get too. |
Gotcha. I misread. You're kinda stuck in that the original componentDidMount name is not really declarative, but calling it componentWillDisplay would make it clear that it's exclusively intended for UI code. |
Just curious. Other than breaking existing code, why not change |
@soupaJ Good question! Breaking existing code is a major factor. It is not just an upgrade path. It is also because existing components that weren't designed for server rendering may just accidentally work. This is an important benefit to growing an ecosystem. For example, lots of npm modules weren't designed to run in a browser but they happen to work because they don't rely on anything in particular which is how things like browserify and webpack got so much use out of it. If you think about it, lots of components rely on You also need some way to differentiate server from client so that you can branch. Might as well make it explicit and branch early. It would also communicate that certain operations are not valid in |
@sebmarkbage This is mostly what I assumed, but wanted to ask anyways :) Good point about being able to communicate when certain operations would not be valid. I didn't think about that. |
|
I think having these would confuse the hell out of beginners, at least if they're named like this. React is already quite verbose but adding even more verbose calls with semantic differences like "was" and "did" that covey no message, address specific use-cases and have major impact behind the scenes ... React wouldn't be simple any longer. Wouldn't it be possible to simply allow the lifecycle hooks that we already have to return promises or functions to be deferred so the internal layer can decide what's best. Functions could get postponed, promises could get rejected or canceled should the need arise (element not visible currently, etc). |
@drcmda I think that's a fair point. I intentionally named them with subtle semantic differences to avoid coming a up with a new naming scheme. We will also need to leave the existing ones in for a very long time to make upgrading smooth. However, I think that some of the existing ones will become edge cases and can be relegated to "legacy". I think we'd probably need to come up with a new naming scheme that highlights the semantic differences between the new set of preferred life-cycles. Perhaps keeping both as an upgrade path for a while. |
I have a use case where I need a hook which fires from timing perspective like I need to render a style sheet for a component. Styles have source order based specificity logic. I want to be able to pass a class name rendered from the parent to the child and that class name needs to have a higher specificity than a class rendered by the child. Styles need to be always rendered before the component dom renders to avoid recalcs and repaints. Now the current state is that a sheet rendered in the parent during |
I'd be interested to see if we could drop the
I'm not bothered on the actual names, I just believe making a clear distinction (a bit like Node did with async vs sync) makes a lot of sense and is a well understood pattern. |
A related problem is how do we invoke |
I think that's correct (see Enzyme compat tests for Although it looks like Enzyme also has a thing called |
Mostly I use the componentWillRecieveProps hook when I need to do something only once on a particular transition (for performance or external communication reasons) otherwise I do everything in the pure render() function. I particularly don't like the following code that has to run to test transitions of interest on each component lifecycle i.e. "if (old_prop==v1 && new_pop==v2)" ... This got me thinking that instead of trying to name life cycle methods, an alternative could be to make the system more declarative and roll the whole thing into a subscription type pattern, with a published list of allowable transitions. What I would like to be able to do is declare that I am interested in subscribing to a particular lifecycle-state transition or change. e.g. registerLifecycleStateTransitionCallback(from_lifecycle_state, to_lifecycle_state, (state, props) => {}, intention, priority) where intention can be a list of flags like will update dom, will update state, etc that could help with the scheduling of the callback. If this is too strict and we want a looser construct, registerLifecycleStateChangeCallback(BEFORE/AFTER, lifecycle_state, (state, props) => {}, intention, priority), which is similar to the current lifecycle methods but without the proliferation of method names. Similarly I'd like a callback for registering interest in individual property transitions e.g. registerPropertyTransitionCallback(from_prop_value, to_prop_value, (props, state) => {}, intention, priority). Again if this is too strict and we need a looser construct registerPropertyChangeCallback(BEFORE/AFTER, prop_name, (state, props) => {}, intention, priority) This could be extended to an AND specification on a set of transitions and/or property changes of interest. |
On @aweary's suggestion I'm moving this idea here:
|
|
RFC for something equivalent to |
The remaining issues are sufficiently covered by linked issues. |
I'll use this gather a few ideas of new life-cycle methods that help avoid existing problematic cases when using Fiber or other async rendering solutions.
componentDidServerRender
: Gets called after the entire tree has rendered on the server. Useful for aborting buffered renders, or logging. Got the idea from Deprecate componentWillMount Maybe? #7671. This could possibly replacecomponentWillMount
.componentWasMounted
andcomponentWasUpdated
: Similar tocomponentDidMount
andcomponentDidUpdate
but happens asynchronously in spare cycles after a component has already appeared on the screen. That way triggering things like I/O doesn't have to block the component from rendering on the screen and dropping frames sincecomponentDidMount
have to be synchronous. This is not appropriate to use for Flux store subscriptions since you may be missing events that way. However, we can use "lazy subscriptions" as an alternative solution. componentWasMounted/componentWasUpdated (formerly componentDidDisplay) #5053.componentWasUnmounted
: Similar to the above, this would happen in spare cycles for clean up purposes where clean up is not synchronously needed. This may not be needed as a separate life-cycles since we can possibly just makecomponentWillUnmount
async. Defer Execution of Unmount Life Cycle Hooks #6003.componentWillMountNow
andcomponentWillUpdateNow
: This would be a fiber specific thing. Unlike the currentcomponentWillMount
/componentWillUpdate
it actually happens afterrender
and after all the children'srender
have been called, but right before any side-effects are committed to the DOM. The use case of reading the current scroll position incomponentWillUpdate
only to reset it later doesn't work with async rendering because you can scroll betweencomponentWillUpdate
andcomponentDidUpdate
. This could possibly replacecomponentWillUpdate
.The text was updated successfully, but these errors were encountered: