react/packages/react-reconciler/src/ReactFiberTreeReflection.js

358 lines
11 KiB
JavaScript
Raw Normal View History

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {Fiber} from './ReactInternalTypes';
import type {Container, SuspenseInstance} from './ReactFiberConfig';
import type {SuspenseState} from './ReactFiberSuspenseComponent';
import {get as getInstance} from 'shared/ReactInstanceMap';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
import {
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
ClassComponent,
HostComponent,
Model Float on Hoistables semantics (#26106) ## Hoistables In the original implementation of Float, all hoisted elements were treated like Resources. They had deduplication semantics and hydrated based on a key. This made certain kinds of hoists very challenging such as sequences of meta tags for `og:image:...` metadata. The reason is each tag along is not dedupable based on only it's intrinsic properties. two identical tags may need to be included and hoisted together with preceding meta tags that describe a semantic object with a linear set of html nodes. It was clear that the concept of Browser Resources (stylesheets / scripts / preloads) did not extend universally to all hositable tags (title, meta, other links, etc...) Additionally while Resources benefit from deduping they suffer an inability to update because while we may have multiple rendered elements that refer to a single Resource it isn't unambiguous which element owns the props on the underlying resource. We could try merging props, but that is still really hard to reason about for authors. Instead we restrict Resource semantics to freezing the props at the time the Resource is first constructed and warn if you attempt to render the same Resource with different props via another rendered element or by updating an existing element for that Resource. This lack of updating restriction is however way more extreme than necessary for instances that get hoisted but otherwise do not dedupe; where there is a well defined DOM instance for each rendered element. We should be able to update props on these instances. Hoistable is a generalization of what Float tries to model for hoisting. Instead of assuming every hoistable element is a Resource we now have two distinct categories, hoistable elements and hoistable resources. As one might guess the former has semantics that match regular Host Components except the placement of the node is usually in the <head>. The latter continues to behave how the original implementation of HostResource behaved with the first iteration of Float ### Hoistable Element On the server hoistable elements render just like regular tags except the output is stored in special queues that can be emitted in the stream earlier than they otherwise would be if rendered in place. This also allow for instance the ability to render a hoistable before even rendering the <html> tag because the queues for hoistable elements won't flush until after we have flushed the preamble (`<DOCTYPE html><html><head>`). On the client, hoistable elements largely operate like HostComponents. The most notable difference is in the hydration strategy. If we are hydrating and encounter a hoistable element we will look for all tags in the document that could potentially be a match and we check whether the attributes match the props for this particular instance. We also do this in the commit phase rather than the render phase. The reason hydration can be done for HostComponents in render is the instance will be removed from the document if hydration fails so mutating it in render is safe. For hoistables the nodes are not in a hydration boundary (Root or SuspenseBoundary at time of writing) and thus if hydration fails and we may have an instance marked as bound to some Fiber when that Fiber never commits. Moving the hydration matching to commit ensures we will always succeed in pairing the hoisted DOM instance with a Fiber that has committed. ### Hoistable Resource On the server and client the semantics of Resources are largely the same they just don't apply to title, meta, and most link tags anymore. Resources hoist and dedupe via an `href` key and are ref counted. In a future update we will add a garbage collector so we can clean up Resources that no longer have any references ## `<style>` support In earlier implementations there was no support for <style> tags. This PR adds support for treating `<style href="..." precedence="...">...</style>` as a Resource analagous to `<link rel="stylesheet" href="..." precedence="..." />` It may seem odd at first to require an href to get Resource semantics for a style tag. The rationale is that these are for inlining of actual external stylesheets as an optimization and for URI like scoping of inline styles for css-in-js libraries. The href indicates that the key space for `<style>` and `<link rel="stylesheet" />` Resources is shared. and the precedence is there to allow for interleaving of both kinds of Style resources. This is an advanced feature that we do not expect most app developers to use directly but will be quite handy for various styling libraries and for folks who want to inline as much as possible once Fizz supports this feature. ## refactor notes * HostResource Fiber type is renamed HostHoistable to reflect the generalization of the concept * The Resource object representation is modified to reduce hidden class checks and to use less memory overall * The thing that distinguishes a resource from an element is whether the Fiber has a memoizedState. If it does, it will use resource semantics, otherwise element semantics * The time complexity of matching hositable elements for hydration should be improved
2023-02-10 14:59:29 +08:00
HostHoistable,
HostSingleton,
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
HostRoot,
HostPortal,
HostText,
Event Replaying (#16725) * Add Event Replaying Infra * Wire up Roots and Suspense boundaries, to retry events, after they commit * Replay discrete events in order in a separate scheduler callback * Add continuous events These events only replay their last target if the target is not yet hydrated. That way we don't have to wait for a previously hovered boundary before invoking the current target. * Enable tests from before These tests were written with replaying in mind and now we can properly enable them. * Unify replaying and dispatching * Mark system flags as a replay and pass to legacy events That way we can check if this is a replay and therefore needs a special case. One such special case is "mouseover" where we check the relatedTarget. * Eagerly listen to all replayable events To minimize breakages in a minor, I only do this for the new root APIs since replaying only matters there anyway. Only if hydrating. For Flare, I have to attach all active listeners since the current system has one DOM listener for each. In a follow up I plan on optimizing that by only attaching one if there's at least one active listener which would allow us to start with only passive and then upgrade. * Desperate attempt to save bytese * Add test for mouseover replaying We need to check if the "relatedTarget" is mounted due to how the old event system dispatches from the "out" event. * Fix for nested boundaries and suspense in root container This is a follow up to #16673 which didn't have a test because it wasn't observable yet. This shows that it had a bug. * Rename RESPONDER_EVENT_SYSTEM to PLUGIN_EVENT_SYSTEM
2019-09-24 02:21:10 +08:00
SuspenseComponent,
} from './ReactWorkTags';
import {NoFlags, Placement, Hydrating} from './ReactFiberFlags';
import {enableFloat, enableHostSingletons} from 'shared/ReactFeatureFlags';
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
export function getNearestMountedFiber(fiber: Fiber): null | Fiber {
let node = fiber;
let nearestMounted: null | Fiber = fiber;
if (!fiber.alternate) {
// If there is no alternate, this might be a new tree that isn't inserted
// yet. If it is, then it will have a pending insertion effect on it.
let nextNode: Fiber = node;
do {
node = nextNode;
if ((node.flags & (Placement | Hydrating)) !== NoFlags) {
// This is an insertion or in-progress hydration. The nearest possible
// mounted fiber is the parent but we need to continue to figure out
// if that one is still mounted.
nearestMounted = node.return;
}
// $FlowFixMe[incompatible-type] we bail out when we get a null
nextNode = node.return;
} while (nextNode);
} else {
while (node.return) {
node = node.return;
}
}
if (node.tag === HostRoot) {
// TODO: Check if this was a nested HostRoot when used with
// renderContainerIntoSubtree.
return nearestMounted;
}
2016-11-22 01:13:26 +08:00
// If we didn't hit the root, that means that we're in an disconnected tree
// that has been unmounted.
return null;
}
Event Replaying (#16725) * Add Event Replaying Infra * Wire up Roots and Suspense boundaries, to retry events, after they commit * Replay discrete events in order in a separate scheduler callback * Add continuous events These events only replay their last target if the target is not yet hydrated. That way we don't have to wait for a previously hovered boundary before invoking the current target. * Enable tests from before These tests were written with replaying in mind and now we can properly enable them. * Unify replaying and dispatching * Mark system flags as a replay and pass to legacy events That way we can check if this is a replay and therefore needs a special case. One such special case is "mouseover" where we check the relatedTarget. * Eagerly listen to all replayable events To minimize breakages in a minor, I only do this for the new root APIs since replaying only matters there anyway. Only if hydrating. For Flare, I have to attach all active listeners since the current system has one DOM listener for each. In a follow up I plan on optimizing that by only attaching one if there's at least one active listener which would allow us to start with only passive and then upgrade. * Desperate attempt to save bytese * Add test for mouseover replaying We need to check if the "relatedTarget" is mounted due to how the old event system dispatches from the "out" event. * Fix for nested boundaries and suspense in root container This is a follow up to #16673 which didn't have a test because it wasn't observable yet. This shows that it had a bug. * Rename RESPONDER_EVENT_SYSTEM to PLUGIN_EVENT_SYSTEM
2019-09-24 02:21:10 +08:00
export function getSuspenseInstanceFromFiber(
fiber: Fiber,
): null | SuspenseInstance {
if (fiber.tag === SuspenseComponent) {
let suspenseState: SuspenseState | null = fiber.memoizedState;
if (suspenseState === null) {
const current = fiber.alternate;
if (current !== null) {
suspenseState = current.memoizedState;
}
}
if (suspenseState !== null) {
return suspenseState.dehydrated;
}
}
return null;
}
export function getContainerFromFiber(fiber: Fiber): null | Container {
return fiber.tag === HostRoot
? (fiber.stateNode.containerInfo: Container)
: null;
}
export function isFiberMounted(fiber: Fiber): boolean {
return getNearestMountedFiber(fiber) === fiber;
}
export function isMounted(component: React$Component<any, any>): boolean {
2017-02-08 03:48:45 +08:00
if (__DEV__) {
2017-03-14 08:05:18 +08:00
const owner = (ReactCurrentOwner.current: any);
if (owner !== null && owner.tag === ClassComponent) {
2017-03-14 08:05:18 +08:00
const ownerFiber: Fiber = owner;
2017-02-08 03:48:45 +08:00
const instance = ownerFiber.stateNode;
if (!instance._warnedAboutRefsInRender) {
console.error(
'%s is accessing isMounted inside its render() function. ' +
'render() should be a pure function of props and state. It should ' +
'never access something that requires stale data from the previous ' +
'render, such as refs. Move this logic to componentDidMount and ' +
'componentDidUpdate instead.',
getComponentNameFromFiber(ownerFiber) || 'A component',
);
}
2017-02-08 03:48:45 +08:00
instance._warnedAboutRefsInRender = true;
}
}
const fiber: ?Fiber = getInstance(component);
if (!fiber) {
return false;
}
return getNearestMountedFiber(fiber) === fiber;
}
function assertIsMounted(fiber: Fiber) {
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
if (getNearestMountedFiber(fiber) !== fiber) {
throw new Error('Unable to find node on an unmounted component.');
}
}
export function findCurrentFiberUsingSlowPath(fiber: Fiber): Fiber | null {
const alternate = fiber.alternate;
if (!alternate) {
// If there is no alternate, then we only need to check if it is mounted.
const nearestMounted = getNearestMountedFiber(fiber);
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
if (nearestMounted === null) {
throw new Error('Unable to find node on an unmounted component.');
}
if (nearestMounted !== fiber) {
return null;
}
return fiber;
}
// If we have two possible branches, we'll walk backwards up to the root
// to see what path the root points to. On the way we may hit one of the
// special cases and we'll deal with them.
let a: Fiber = fiber;
let b: Fiber = alternate;
while (true) {
const parentA = a.return;
if (parentA === null) {
// We're at the root.
break;
}
const parentB = parentA.alternate;
if (parentB === null) {
// There is no alternate. This is an unusual case. Currently, it only
// happens when a Suspense component is hidden. An extra fragment fiber
// is inserted in between the Suspense fiber and its children. Skip
// over this extra fragment fiber and proceed to the next parent.
const nextParent = parentA.return;
if (nextParent !== null) {
a = b = nextParent;
continue;
}
// If there's no parent, we're at the root.
break;
}
2017-01-31 10:41:25 +08:00
// If both copies of the parent fiber point to the same child, we can
// assume that the child is current. This happens when we bailout on low
// priority: the bailed out fiber's child reuses the current child.
if (parentA.child === parentB.child) {
let child = parentA.child;
while (child) {
if (child === a) {
// We've determined that A is the current branch.
assertIsMounted(parentA);
return fiber;
}
if (child === b) {
// We've determined that B is the current branch.
assertIsMounted(parentA);
return alternate;
}
child = child.sibling;
}
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
// We should never have an alternate for any mounting node. So the only
// way this could possibly happen is if this was unmounted, if at all.
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
throw new Error('Unable to find node on an unmounted component.');
}
2017-01-31 10:41:25 +08:00
if (a.return !== b.return) {
// The return pointer of A and the return pointer of B point to different
// fibers. We assume that return pointers never criss-cross, so A must
// belong to the child set of A.return, and B must belong to the child
// set of B.return.
a = parentA;
b = parentB;
} else {
// The return pointers point to the same fiber. We'll have to use the
2017-01-31 10:41:25 +08:00
// default, slow path: scan the child sets of each parent alternate to see
// which child belongs to which set.
//
// Search parent A's child set
let didFindChild = false;
let child = parentA.child;
while (child) {
if (child === a) {
didFindChild = true;
a = parentA;
b = parentB;
break;
}
if (child === b) {
didFindChild = true;
b = parentA;
a = parentB;
break;
}
child = child.sibling;
}
if (!didFindChild) {
// Search parent B's child set
child = parentB.child;
while (child) {
if (child === a) {
didFindChild = true;
2017-01-31 10:41:25 +08:00
a = parentB;
b = parentA;
break;
}
if (child === b) {
didFindChild = true;
2017-01-31 10:41:25 +08:00
b = parentB;
a = parentA;
break;
}
child = child.sibling;
}
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
if (!didFindChild) {
throw new Error(
'Child was not found in either parent set. This indicates a bug ' +
'in React related to the return pointer. Please file an issue.',
);
}
2017-01-31 10:41:25 +08:00
}
}
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
if (a.alternate !== b) {
throw new Error(
"Return fibers should always be each others' alternates. " +
'This error is likely caused by a bug in React. Please file an issue.',
);
}
}
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
// If the root is not a host container, we're in a disconnected tree. I.e.
// unmounted.
[RFC] Codemod invariant -> throw new Error (#22435) * Hoist error codes import to module scope When this code was written, the error codes map (`codes.json`) was created on-the-fly, so we had to lazily require from inside the visitor. Because `codes.json` is now checked into source, we can import it a single time in module scope. * Minify error constructors in production We use a script to minify our error messages in production. Each message is assigned an error code, defined in `scripts/error-codes/codes.json`. Then our build script replaces the messages with a link to our error decoder page, e.g. https://reactjs.org/docs/error-decoder.html/?invariant=92 This enables us to write helpful error messages without increasing the bundle size. Right now, the script only works for `invariant` calls. It does not work if you throw an Error object. This is an old Facebookism that we don't really need, other than the fact that our error minification script relies on it. So, I've updated the script to minify error constructors, too: Input: Error(`A ${adj} message that contains ${noun}`); Output: Error(formatProdErrorMessage(ERR_CODE, adj, noun)); It only works for constructors that are literally named Error, though we could add support for other names, too. As a next step, I will add a lint rule to enforce that errors written this way must have a corresponding error code. * Minify "no fallback UI specified" error in prod This error message wasn't being minified because it doesn't use invariant. The reason it didn't use invariant is because this particular error is created without begin thrown — it doesn't need to be thrown because it's located inside the error handling part of the runtime. Now that the error minification script supports Error constructors, we can minify it by assigning it a production error code in `scripts/error-codes/codes.json`. To support the use of Error constructors more generally, I will add a lint rule that enforces each message has a corresponding error code. * Lint rule to detect unminified errors Adds a lint rule that detects when an Error constructor is used without a corresponding production error code. We already have this for `invariant`, but not for regular errors, i.e. `throw new Error(msg)`. There's also nothing that enforces the use of `invariant` besides convention. There are some packages where we don't care to minify errors. These are packages that run in environments where bundle size is not a concern, like react-pg. I added an override in the ESLint config to ignore these. * Temporarily add invariant codemod script I'm adding this codemod to the repo temporarily, but I'll revert it in the same PR. That way we don't have to check it in but it's still accessible (via the PR) if we need it later. * [Automated] Codemod invariant -> Error This commit contains only automated changes: npx jscodeshift -t scripts/codemod-invariant.js packages --ignore-pattern="node_modules/**/*" yarn linc --fix yarn prettier I will do any manual touch ups in separate commits so they're easier to review. * Remove temporary codemod script This reverts the codemod script and ESLint config I added temporarily in order to perform the invariant codemod. * Manual touch ups A few manual changes I made after the codemod ran. * Enable error code transform per package Currently we're not consistent about which packages should have their errors minified in production and which ones should. This adds a field to the bundle configuration to control whether to apply the transform. We should decide what the criteria is going forward. I think it's probably a good idea to minify any package that gets sent over the network. So yes to modules that run in the browser, and no to modules that run on the server and during development only.
2021-10-01 03:01:28 +08:00
if (a.tag !== HostRoot) {
throw new Error('Unable to find node on an unmounted component.');
}
if (a.stateNode.current === a) {
// We've determined that A is the current branch.
return fiber;
}
// Otherwise B has to be current branch.
return alternate;
}
export function findCurrentHostFiber(parent: Fiber): Fiber | null {
const currentParent = findCurrentFiberUsingSlowPath(parent);
return currentParent !== null
? findCurrentHostFiberImpl(currentParent)
: null;
}
function findCurrentHostFiberImpl(node: Fiber): Fiber | null {
// Next we'll drill down this component to find the first HostComponent/Text.
const tag = node.tag;
if (
tag === HostComponent ||
Model Float on Hoistables semantics (#26106) ## Hoistables In the original implementation of Float, all hoisted elements were treated like Resources. They had deduplication semantics and hydrated based on a key. This made certain kinds of hoists very challenging such as sequences of meta tags for `og:image:...` metadata. The reason is each tag along is not dedupable based on only it's intrinsic properties. two identical tags may need to be included and hoisted together with preceding meta tags that describe a semantic object with a linear set of html nodes. It was clear that the concept of Browser Resources (stylesheets / scripts / preloads) did not extend universally to all hositable tags (title, meta, other links, etc...) Additionally while Resources benefit from deduping they suffer an inability to update because while we may have multiple rendered elements that refer to a single Resource it isn't unambiguous which element owns the props on the underlying resource. We could try merging props, but that is still really hard to reason about for authors. Instead we restrict Resource semantics to freezing the props at the time the Resource is first constructed and warn if you attempt to render the same Resource with different props via another rendered element or by updating an existing element for that Resource. This lack of updating restriction is however way more extreme than necessary for instances that get hoisted but otherwise do not dedupe; where there is a well defined DOM instance for each rendered element. We should be able to update props on these instances. Hoistable is a generalization of what Float tries to model for hoisting. Instead of assuming every hoistable element is a Resource we now have two distinct categories, hoistable elements and hoistable resources. As one might guess the former has semantics that match regular Host Components except the placement of the node is usually in the <head>. The latter continues to behave how the original implementation of HostResource behaved with the first iteration of Float ### Hoistable Element On the server hoistable elements render just like regular tags except the output is stored in special queues that can be emitted in the stream earlier than they otherwise would be if rendered in place. This also allow for instance the ability to render a hoistable before even rendering the <html> tag because the queues for hoistable elements won't flush until after we have flushed the preamble (`<DOCTYPE html><html><head>`). On the client, hoistable elements largely operate like HostComponents. The most notable difference is in the hydration strategy. If we are hydrating and encounter a hoistable element we will look for all tags in the document that could potentially be a match and we check whether the attributes match the props for this particular instance. We also do this in the commit phase rather than the render phase. The reason hydration can be done for HostComponents in render is the instance will be removed from the document if hydration fails so mutating it in render is safe. For hoistables the nodes are not in a hydration boundary (Root or SuspenseBoundary at time of writing) and thus if hydration fails and we may have an instance marked as bound to some Fiber when that Fiber never commits. Moving the hydration matching to commit ensures we will always succeed in pairing the hoisted DOM instance with a Fiber that has committed. ### Hoistable Resource On the server and client the semantics of Resources are largely the same they just don't apply to title, meta, and most link tags anymore. Resources hoist and dedupe via an `href` key and are ref counted. In a future update we will add a garbage collector so we can clean up Resources that no longer have any references ## `<style>` support In earlier implementations there was no support for <style> tags. This PR adds support for treating `<style href="..." precedence="...">...</style>` as a Resource analagous to `<link rel="stylesheet" href="..." precedence="..." />` It may seem odd at first to require an href to get Resource semantics for a style tag. The rationale is that these are for inlining of actual external stylesheets as an optimization and for URI like scoping of inline styles for css-in-js libraries. The href indicates that the key space for `<style>` and `<link rel="stylesheet" />` Resources is shared. and the precedence is there to allow for interleaving of both kinds of Style resources. This is an advanced feature that we do not expect most app developers to use directly but will be quite handy for various styling libraries and for folks who want to inline as much as possible once Fizz supports this feature. ## refactor notes * HostResource Fiber type is renamed HostHoistable to reflect the generalization of the concept * The Resource object representation is modified to reduce hidden class checks and to use less memory overall * The thing that distinguishes a resource from an element is whether the Fiber has a memoizedState. If it does, it will use resource semantics, otherwise element semantics * The time complexity of matching hositable elements for hydration should be improved
2023-02-10 14:59:29 +08:00
(enableFloat ? tag === HostHoistable : false) ||
(enableHostSingletons ? tag === HostSingleton : false) ||
tag === HostText
) {
return node;
}
let child = node.child;
while (child !== null) {
const match = findCurrentHostFiberImpl(child);
if (match !== null) {
return match;
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
}
child = child.sibling;
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
}
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
return null;
}
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
export function findCurrentHostFiberWithNoPortals(parent: Fiber): Fiber | null {
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
const currentParent = findCurrentFiberUsingSlowPath(parent);
return currentParent !== null
? findCurrentHostFiberWithNoPortalsImpl(currentParent)
: null;
}
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
function findCurrentHostFiberWithNoPortalsImpl(node: Fiber): Fiber | null {
Add warning for rendering into container that was updated manually (#10210) * RFC Add warning for rendering into container that was updated manually RFC because we still need to tidy this up and verify that all tests pass. **what is the change?:** We want to warn when users render into a container which was manually emptied or updated outside of React. This can lead to the cryptic error about not being able to remove a node, or just lead to silent failures of render. This warning should make things more clear. Note that this covers the case where the contents of the root container are manually updated, but does not cover the case where something was manually updated deeper in the tree. **why make this change?:** To maintain parity and increase clarity before releasing v16.0 beta. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 last item under the '16 beta' checklist. * Add test and tweak check for rendering into manually updated container STILL TODO: figure out how to skip this warning when the component renders to a portal. Unfortunately 'ReactPortal.isPortal(children)' returns false, even in the failing test where we are rendering to a portal. **what is the change?:** - added a test for the case where we call 'ReactDOM.render' with a new container, using a key or a different type, after the contents of the first container were messed with outside of React. This case throws, and now at least there will be an informative warning along with the error. - We updated the check to compare the parent of the 'hostInstance' to the container; this seems less fragile - tweaked some comments **why make this change?:** Continue improving this to make it more final. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Stub our `console.error` in one of the portal tests **what is the change?:** See title **why make this change?:** See comment in the code **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Skip warning in 'ReactDOMFiberEntry' when mounting to Comment node **what is the change?:** We have a warning for cases when the container doesn't match the parent which we remembered the previously rendered content being rendered into. We are skipping that warning when you render into a 'comment' node. **why make this change?:** Basically, if you render into a 'comment' node, then the parent of the comment node is the container for your rendered content. We could check for similarity there but rendering into a comment node seems like a corner case and I'd rather skip the warning without knowing more about what could happen in that case. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Improve warning message, remove dedup check, and unmock console.error **what is the change?:** Various changes to get this closer to being finished; - Improved warning message (thanks @spicyj!!!) - Removed dedup check on warning - Remove mocking of 'console.error' in portals test **why make this change?:** - warning message improvement: communicates better with users - Remove dedup check: it wasn't important in this case - Remove mocking of 'console.error'; we don't want to ignore an inaccurate warning, even for an "unstable" feature. **test plan:** `yarn test` -> follow-up commits will fix the remaining tests **issue:** issue #8854 * Possible fix for issue of incorrect warning for portal re-render **what is the change?:** Add a property to a container which was rendered into using `ReactDOM.unstable_createPortal`. **why make this change?:** We don't want to warn for mismatching container nodes in this case - the user intentionally rendered into the portal container instead of the original container. concerns; - will this affect React Native badly? - will this add bloat to the portal code? seems small enough but not sure. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fix logic for checking if the host instance container is a portal **what is the change?:** When focusing on fixing the warning to not check when we are using portals, I missed checking for the existence of the host instance parent before checking if it was a portal. This adds the missing null checks. **why make this change?:** To fix a bug that the previous commit introduced. **test plan:** `yarn test` -> follow-up commits fix more of the test failures **issue:** https://github.com/facebook/react/issues/8854 * Clean up new tests in ReactDOMFiber-test **what is the change?:** - removed extra single quotes, downgrade double quotes to single - update expected warning message to match latest warning message - fix indentation **why make this change?:** - get tests passing - code maintainability/readability **test plan:** `yarn test` follow up commits will fix the remaining tests **issue:** https://github.com/facebook/react/issues/8854 * Add 'unmountComponentAtNode' call in test for reconciling pre-rendered markup **what is the change?:** We have a test that verifies React can reconcile text from pre-rendered mark-up. It tests React doing this for three strings and three empty strings. This adds a call to 'unmountComponentAtNode' between the two expectations for strings and empty strings. **why make this change?:** We now warn when someone messes with the DOM inside of a node in such a way that removes the React-rendered content. This test was doing that. I can't think of a situation where this would happen with server-side rendering without the need to call 'unmountComponentAtNode' before inserting the server-side rendered content. **test plan:** `yarn test` Only one more failing test, will fix that in the next commit. **issue:** https://github.com/facebook/react/issues/8854 * ran prettier * remove unused variable * run scripts/fiber/record-tests * Fix type error and improve name of portal container flag **NOTE:** I am still looking for a good place to move this flag assignment to, or a better approach. This does some intermediate fixes. **what is the change?:** - fixed flow error by allowing optional flag on a DOMContainer that indicates it was used as a portal container. - renamed the flag to something which makes more sense **why make this change?:** - get Flow passing - make this change make more sense We are still not sure about adding this flag; a follow-up diff may move it or take a different approach. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Add flag to portalContainer on mount instead of in `createPortal` **what is the change?:** We add a flag to the container of a 'portal' in the 'commit work' phase in Fiber. This is right before we call `appendChildToContainer`. **why make this change?:** - Sometimes people call `ReactDOM.render(... container)`, then manually clear the content of the `container`, and then try to call another `ReactDOM.render(... container)`. - This leads to cryptic errors or silent failure because we hold a reference to the node that was rendered the first time, and expect it to still be inside the container. - We added a warning for this issue in `renderSubtreeIntoContainer`, but when a component renders something returned by `ReactDOM.unstable_createPortal(<Component />, portalContainer);`, then the child is inside the `portalContainer` and not the `container, but that is valid and we want to skip warning in that case. Inside `renderSubtreeIntoContainer` we don't have the info to determine if a child was rendered into a `portalContainer` or a `container`, and adding this flag lets us figure that out and skip the warning. We originally added the flag in the call to `ReactDOM.unstable_createPortal` but that seemed like a method that should be "pure" and free of side-effects. This commit moves the flag-adding to happen when we mount the portal component. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Force an 'any' type for the `hostInstance.parentNode` in warning check **what is the change?:** This is awful. :( I'm not sure how else to let Flow know that we expect that this might be a sort of `DOMContainer` type and not just a normal `Node` type. To at least make the type information clear we added a comment. **why make this change?:** To get `flow` passing. Looks like we have `any` types sprinkled throughout this file. phooey. :( **test plan:** `yarn flow` **issue:** https://github.com/facebook/react/issues/8854 * Ignore portals in `DOMRenderer.findHostInstance` **what is the change?:** We want to ignore portals when firing a certain warning. This allows us to get the host instance and ignore portals. Also added a new snapshot recording while fixing things. **why make this change?:** Originally we had added a flag to the DOM node which was used for rendering the portal, and then could notice and ignore children rendered into those nodes. However, it's better to just ignore portals in `DOMRenderer.findHostInstance` because - we will not ignore a non-portal second child with this approach - we meant to ignore portals in this method anyway (according to a 'TODO' comment) - this change only affects the DOM renderer, instead of changing code which is shared with RN and other renderers - we avoid adding unneeded expandos **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Ran prettier * Remove error snapshot test I think there is a bug where an empty snapshot is treated as an 'outdated snapshot'. If I delete the obsolute snapshot, and run ReactDOMFiber-test.js it generates a new snapshot. But then when I run the test with the newly generated snapshot, it says "1 obsolete snapshot found", At some point I will file an issue with Jest. For now going to skip the snapshot generation for the error message in the new test. * Remove expando that we were adding to portal container **what is the change?:** see title **why make this change?:** this is part of an old approach to detecting portals, and we have instead added a check in the `findHostInstance` method to filter out portals. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854 * Fork `findHostInstance` to make `findHostInstanceWithNoPortals` **what is the change?:** We need to get host instances, but filter out portals. There is not currently a method for that. **why make this change?:** Rather than change the existing `findHostInstance` method, which would affect the behavior of the public `findDOMNode` method, we are forking. **test plan:** `yarn test` **issue:** https://github.com/facebook/react/issues/8854
2017-07-21 23:48:46 +08:00
// Next we'll drill down this component to find the first HostComponent/Text.
const tag = node.tag;
if (
tag === HostComponent ||
Model Float on Hoistables semantics (#26106) ## Hoistables In the original implementation of Float, all hoisted elements were treated like Resources. They had deduplication semantics and hydrated based on a key. This made certain kinds of hoists very challenging such as sequences of meta tags for `og:image:...` metadata. The reason is each tag along is not dedupable based on only it's intrinsic properties. two identical tags may need to be included and hoisted together with preceding meta tags that describe a semantic object with a linear set of html nodes. It was clear that the concept of Browser Resources (stylesheets / scripts / preloads) did not extend universally to all hositable tags (title, meta, other links, etc...) Additionally while Resources benefit from deduping they suffer an inability to update because while we may have multiple rendered elements that refer to a single Resource it isn't unambiguous which element owns the props on the underlying resource. We could try merging props, but that is still really hard to reason about for authors. Instead we restrict Resource semantics to freezing the props at the time the Resource is first constructed and warn if you attempt to render the same Resource with different props via another rendered element or by updating an existing element for that Resource. This lack of updating restriction is however way more extreme than necessary for instances that get hoisted but otherwise do not dedupe; where there is a well defined DOM instance for each rendered element. We should be able to update props on these instances. Hoistable is a generalization of what Float tries to model for hoisting. Instead of assuming every hoistable element is a Resource we now have two distinct categories, hoistable elements and hoistable resources. As one might guess the former has semantics that match regular Host Components except the placement of the node is usually in the <head>. The latter continues to behave how the original implementation of HostResource behaved with the first iteration of Float ### Hoistable Element On the server hoistable elements render just like regular tags except the output is stored in special queues that can be emitted in the stream earlier than they otherwise would be if rendered in place. This also allow for instance the ability to render a hoistable before even rendering the <html> tag because the queues for hoistable elements won't flush until after we have flushed the preamble (`<DOCTYPE html><html><head>`). On the client, hoistable elements largely operate like HostComponents. The most notable difference is in the hydration strategy. If we are hydrating and encounter a hoistable element we will look for all tags in the document that could potentially be a match and we check whether the attributes match the props for this particular instance. We also do this in the commit phase rather than the render phase. The reason hydration can be done for HostComponents in render is the instance will be removed from the document if hydration fails so mutating it in render is safe. For hoistables the nodes are not in a hydration boundary (Root or SuspenseBoundary at time of writing) and thus if hydration fails and we may have an instance marked as bound to some Fiber when that Fiber never commits. Moving the hydration matching to commit ensures we will always succeed in pairing the hoisted DOM instance with a Fiber that has committed. ### Hoistable Resource On the server and client the semantics of Resources are largely the same they just don't apply to title, meta, and most link tags anymore. Resources hoist and dedupe via an `href` key and are ref counted. In a future update we will add a garbage collector so we can clean up Resources that no longer have any references ## `<style>` support In earlier implementations there was no support for <style> tags. This PR adds support for treating `<style href="..." precedence="...">...</style>` as a Resource analagous to `<link rel="stylesheet" href="..." precedence="..." />` It may seem odd at first to require an href to get Resource semantics for a style tag. The rationale is that these are for inlining of actual external stylesheets as an optimization and for URI like scoping of inline styles for css-in-js libraries. The href indicates that the key space for `<style>` and `<link rel="stylesheet" />` Resources is shared. and the precedence is there to allow for interleaving of both kinds of Style resources. This is an advanced feature that we do not expect most app developers to use directly but will be quite handy for various styling libraries and for folks who want to inline as much as possible once Fizz supports this feature. ## refactor notes * HostResource Fiber type is renamed HostHoistable to reflect the generalization of the concept * The Resource object representation is modified to reduce hidden class checks and to use less memory overall * The thing that distinguishes a resource from an element is whether the Fiber has a memoizedState. If it does, it will use resource semantics, otherwise element semantics * The time complexity of matching hositable elements for hydration should be improved
2023-02-10 14:59:29 +08:00
(enableFloat ? tag === HostHoistable : false) ||
(enableHostSingletons ? tag === HostSingleton : false) ||
tag === HostText
) {
return node;
}
let child = node.child;
while (child !== null) {
if (child.tag !== HostPortal) {
const match = findCurrentHostFiberWithNoPortalsImpl(child);
if (match !== null) {
return match;
}
}
child = child.sibling;
}
return null;
}
export function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean {
const memoizedState = fiber.memoizedState;
return (
fiber.tag === SuspenseComponent &&
memoizedState !== null &&
memoizedState.dehydrated === null
);
}
export function doesFiberContain(
parentFiber: Fiber,
childFiber: Fiber,
): boolean {
let node: null | Fiber = childFiber;
const parentFiberAlternate = parentFiber.alternate;
while (node !== null) {
if (node === parentFiber || node === parentFiberAlternate) {
return true;
}
node = node.return;
}
return false;
}