Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why does React warn about multiple renderers using the same context provider? #19519

Closed
vimcaw opened this issue Aug 3, 2020 · 2 comments
Closed

Comments

@vimcaw
Copy link

vimcaw commented Aug 3, 2020

I am currently developing a web app that uses both react-pixi and react-babylonjs. Both of these libraries use react-reconciler and have a custom renderer. I also use redux in my project, so they share the same Context in the two libraries.

It displays a warning on Console after every redux state updating, but everything works well, both renderers can trigger an update.

I want to know if there is any risk in doing this, or is this just a false warning?

React version: 16.13.1

Steps To Reproduce

  1. Using multiple react renderers
  2. Using the same context provider between that react renderers

Link to code example: https://codesandbox.io/s/multiple-reconciler-using-same-context-v8kq1?file=/src/App.js

The current behavior

It will throw a warning message after every state updating:

Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.

But everything works well, both renderers can trigger an update.

The expected behavior

Don't show any warning.

@vimcaw vimcaw added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Aug 3, 2020
@bvaughn
Copy link
Contributor

bvaughn commented Aug 3, 2020

React only supports two concurrent renderers at most– one "primary" and one "secondary", e.g. React DOM (primary) and React ART (secondary) or React Native (primary) and Fabric (secondary). This is partially a practical constraint (in that it covers 99% of use cases) and partially an intentional trade off in that certain APIs (like Context or useMutableSource) are able to be more efficiently implemented because of it.

For example, rather than using a (slower) Map structure to maintain a (per-renderer) stack of context values, the Context API is able to store this stack on the context object using a designated field:

if (isPrimaryRenderer) {
push(valueCursor, context._currentValue, providerFiber);
context._currentValue = nextValue;
if (__DEV__) {
if (
context._currentRenderer !== undefined &&
context._currentRenderer !== null &&
context._currentRenderer !== rendererSigil
) {
console.error(
'Detected multiple renderers concurrently rendering the ' +
'same context provider. This is currently unsupported.',
);
}
context._currentRenderer = rendererSigil;
}
} else {
push(valueCursor, context._currentValue2, providerFiber);
context._currentValue2 = nextValue;
if (__DEV__) {
if (
context._currentRenderer2 !== undefined &&
context._currentRenderer2 !== null &&
context._currentRenderer2 !== rendererSigil
) {
console.error(
'Detected multiple renderers concurrently rendering the ' +
'same context provider. This is currently unsupported.',
);
}
context._currentRenderer2 = rendererSigil;
}

Same for the useMutableSource API:

export function resetWorkInProgressVersions(): void {
for (let i = 0; i < workInProgressSources.length; i++) {
const mutableSource = workInProgressSources[i];
if (isPrimaryRenderer) {
mutableSource._workInProgressVersionPrimary = null;
} else {
mutableSource._workInProgressVersionSecondary = null;
}
}
workInProgressSources.length = 0;
}
export function getWorkInProgressVersion(
mutableSource: MutableSource<any>,
): null | MutableSourceVersion {
if (isPrimaryRenderer) {
return mutableSource._workInProgressVersionPrimary;
} else {
return mutableSource._workInProgressVersionSecondary;
}
}
export function setWorkInProgressVersion(
mutableSource: MutableSource<any>,
version: MutableSourceVersion,
): void {
if (isPrimaryRenderer) {
mutableSource._workInProgressVersionPrimary = version;
} else {
mutableSource._workInProgressVersionSecondary = version;
}
workInProgressSources.push(mutableSource);
}

Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.

This warning suggests that two renderers of the same type (presumably two primary renderers) are both using a context at the same time (concurrently). This might happen to work okay in some cases (e.g. if only the global/default context value is being used) but it may also break depending on how each renderer is using the context.

Hope this helps answer your question! tl;dr is that the warning is valid and important.

@bvaughn bvaughn closed this as completed Aug 3, 2020
@bvaughn bvaughn added Type: Question and removed Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug labels Aug 3, 2020
@bvaughn bvaughn changed the title Bug: about warning when using the same context provider between multiple react reconcilers Why does React warn about multiple renderers using the same context provider? Aug 3, 2020
@vimcaw
Copy link
Author

vimcaw commented Aug 4, 2020

Thank you for such a detailed answer! now I understand.

Both of react-pixi and react-babylonjs have a custom renderer, plus the original react-dom, there are 3 renderers, seems I must give up one of them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants