Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Conversation

@nanovazquez
Copy link
Contributor

@nanovazquez nanovazquez commented May 19, 2018

This PR updates the code to use the displayName for the new React 16.3 Context API components. It includes the following changes:

  • Creates ContextProvider and ContextConsumer node types for context providers and consumers. This way, we can identify these nodes by using their types, instead of their names.
    • Adds logic to use displayName for context providers and consumers' name, if present.
    • Updates logic to colorize context providers and consumers nodes with the same color used for Composite nodes.
  • Updates TraceUpdatesBackendManager to highlight updates in Context Consumer nodes. For this, it checks the type instead of the name.
  • Updates the "plain" example by adding React.createContext, using one of ThemeContext examples in React's documentation.

Before

React Devtools wasn't picking up the displayName or colorizing these nodes.

image

After

const ThemeContext = React.createContext();
ThemeContext.Provider.displayName = 'ThemeContext.Provider';
ThemeContext.Consumer.displayName = 'ThemeContext.Consumer';

image

If there is no display name in the Context components, React Devtools falls back to default values (<Context.Provider> and <Context.Consumer> respectively).

image

@benwiley4000
Copy link

benwiley4000 commented Sep 7, 2018

I'd love for this to be merged - @nanovazquez are you able to solve the merge conflict?

ETA: just so we're clear I have no say in whether this gets merged 😄

@nanovazquez nanovazquez force-pushed the master branch 2 times, most recently from 0c39351 to efb5ba5 Compare September 11, 2018 21:42
@nanovazquez
Copy link
Contributor Author

@benwiley4000 done! 😄

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

I have not thought about this much, but my initial thought is that this would be a preferable API:

const ThemeContext = React.createContext();
ThemeContext.displayName = 'ThemeContext';

Then we could do something like:

case CONTEXT_PROVIDER_NUMBER:
case CONTEXT_PROVIDER_SYMBOL_STRING:
  nodeType = 'Special';
  props = fiber.memoizedProps;
  name = `${fiber.type._context.displayName || 'Context'}.Provider`;
  children = [];
  break;
case CONTEXT_CONSUMER_NUMBER:
case CONTEXT_CONSUMER_SYMBOL_STRING:
  nodeType = 'Special';
  props = fiber.memoizedProps;
  name = `${fiber.type.displayName || 'Context'}.Consumer`;
  children = [];
  break;

I'm also not sure about the coloring change. Seems unrelated to the core of the PR. Context.Provider and Context.Consumer aren't user-defined components so it seems a bit odd to color them the same as function and class components.

FWIW you can probably avoid most of the merge conflicts that require rebasing by not committing files from test/example/build. (Those can be regenerated easily using yarn build:example by the reviewer.)

@benwiley4000
Copy link

@bvaughn I agree it would be nice to be able to not repeat yourself, but I think the least surprising thing would be to at least support putting the displayName directly on the consumer and the provider (which works for every other type of react component), and then maybe what you suggested.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

but I think the least surprising thing would be to at least support putting the displayName directly on the consumer and the provider (which works for every other type of react component)

I don't think this is really true? It works for user-defined function and class components– and the user-supplied render function passed to forwardRef– but you wouldn't expect to put a display name on e.g. StrictMode or unstable_AsyncMode types. And since these types are Symbols, it wouldn't work if you tried.

@benwiley4000
Copy link

@bvaughn ok sorry I did misspeak. I was really referring to user-defined components. The thing is that even though context components are created via a special factory, you (meaning I :) ) expect to be able to name them directly anyway because they feel like components I created. Unlike StrictMode or the like, Context.Consumer is specially instanced for my own purposes.

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

Yeah, I can understand that point of view. I think my preference is still the same though. 😄

Another tiny reason why naming the context object feels preferable is that it avoids potentially mismatched names.

@benwiley4000
Copy link

Yeah, that's a good point

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

I'm going to plug in my own change and do a little testing. If it seems good, I'll merge.

@bvaughn bvaughn merged commit 60ad5e6 into facebook:master Sep 20, 2018
@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

Thanks! I've merged this. As of the next release, this should be supported:

const ThemeContext = React.createContext();
ThemeContext.displayName = 'ThemeContext';

@benwiley4000
Copy link

Thanks!!

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

Thanks for your patience 😄

@bvaughn
Copy link
Contributor

bvaughn commented Sep 20, 2018

Released with 3.4.0

@jaydenseric
Copy link

jaydenseric commented Sep 21, 2018

It doesn't feel intuitive that you can't set the display name separately on provider and consumer components; they are different components after all. A lot of libraries export a provider, called things like ExampleProvider, and don't necessarily export a consumer (it may be used internally in another exported component).

Here is an intuitive API:

// example-lib.js

import React from 'react'

const {
  Provider: ExampleProvider,
  Consumer: ExampleConsumer
} = React.createContext()

ExampleProvider.displayName = 'ExampleProvider'
ExampleConsumer.displayName = 'ExampleConsumer'

export { ExampleProvider, ExampleConsumer }
import React from 'react'
import { ExampleProvider } from 'example-lib'

const example = ''

const App = () => (
  <ExampleProvider value={example}>
    {/* Stuff */}
  </ExampleProvider>
)

It should display exactly as ExampleProvider in dev tools, as that is the name of the component users are importing and using.

If I were to rethink the context API to make this easier, perhaps it could be:

import React from 'react'

const {
  ExampleProvider,
  ExampleConsumer
} = React.createContext(
  // Custom provider component name:
  'ExampleProvider',
  // Custom consumer component name:
  'ExampleConsumer'
)

@bvaughn
Copy link
Contributor

bvaughn commented Sep 21, 2018

React.createContext() already accepts a value– the default value for context. (This value also enables static type checking via Flow.) Customizing the display name of a component in DevTools is an advanced, nuanced case and I don't think it will ever be directly referenced as part of any of React's APIs.

I don't personally see why "ExampleProvider" and "ExampleConsumer" are inherently better than "Example.Provider" and "Example.Consumer". If anything, the latter provides a bit more of a visual cue that the two components are closely related as part of a single thing (the "Example" context).

@benwiley4000
Copy link

Agree with @bvaughn's reasoning, especially because ExampleProvider is the name I end up giving to the wrapper component which holds all the "smarts". :)

@armand1m
Copy link

@jaydenseric why would you want to give a different name to the provider and the consumer since they rely in the same context?

@bisubus
Copy link

bisubus commented Oct 13, 2018

From this PR, I'm still unsure how does it work if we set displayName only once?

const ThemeContext = React.createContext();
ThemeContext.displayName = 'MyThemeContext';

I would expect that <ThemeContext.Consumer> will be shown as <MyThemeContext.Consumer> because ThemeContext is actually a consumer, ThemeContext === ThemeContext.Consumer>. And <ThemeContext.Provider> will be shown as <MyThemeContext.Provider>, because a consumer and a provider are closely related.

I supposed this is roughly the same as this comment says about.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants