Giter VIP home page Giter VIP logo

Comments (10)

bvaughn avatar bvaughn commented on May 20, 2024

This is interesting. I can't repro it in a test app created to try to trigger it:
https://tj8xl.csb.app/

All ways of selecting one of the rows (the selector tool, right click + "inspect", scroll and click in Elements tab) successfully sync up with the DevTools Components tab.

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

I can if I add a second React root. I think that might be the cause somehow.

Update: I could for a little while and now I can't again 😁

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

The flow of code for this feature is...

  1. DevTools backend listens for a new selection in the browser's Elements tab and sets a flag (needsToSyncElementSelection):

    setReactSelectionFromBrowser();
    chrome.devtools.panels.elements.onSelectionChanged.addListener(() => {
    setReactSelectionFromBrowser();
    });

  2. Right before the Components tab is shown again, if this flag has been marked, it notifies the UI to update the selection:

    chrome.devtools.panels.create('⚛ Components', '', 'panel.html', panel => {
    panel.onShown.addListener(panel => {
    if (needsToSyncElementSelection) {
    needsToSyncElementSelection = false;
    bridge.send('syncSelectionFromNativeElementsPanel');
    }

  3. The Agent in the middle listens for this:

    syncSelectionFromNativeElementsPanel = () => {
    const target = window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$0;
    if (target == null) {
    return;
    }
    this.selectNode(target);
    };

  4. And forwards it on to the frontend:

    selectNode(target: Object): void {
    const id = this.getIDForNode(target);
    if (id !== null) {
    this._bridge.send('selectFiber', id);
    }
    }

  5. The frontend listens for this and updates its state:

    // Listen for host element selections.
    useEffect(() => {
    const handleSelectFiber = (id: number) =>
    dispatchWrapper({ type: 'SELECT_ELEMENT_BY_ID', payload: id });
    bridge.addListener('selectFiber', handleSelectFiber);
    return () => bridge.removeListener('selectFiber', handleSelectFiber);
    }, [bridge, dispatchWrapper]);

  6. Lastly the Tree UI listens for a change in state, and triggers the scroll to:

    // Make sure a newly selected element is visible in the list.
    // This is helpful for things like the owners list and search.
    useLayoutEffect(() => {
    if (selectedElementIndex !== null && listRef.current != null) {
    listRef.current.scrollToItem(selectedElementIndex, 'smart');
    // Note this autoscroll only works for rows.
    // There's another autoscroll inside the elements
    // that ensures the component name is visible horizontally.
    // It's too early to do it now because the row might not exist yet.
    }
    }, [listRef, selectedElementIndex]);

Looks like all of these things are working as expected (in that the selection is being updated) except for the scroll operation. It works some (most?) of the time but not always.

Maybe this could indicate that, in some cases, the DevTools panel (and the tree/list inside of it) has an initial height of 0 or something?

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

If I force a height of 0, (by opening the bottom pop-out console so it completely covers DevTools), I can force this to happen.

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

Maybe this could indicate that, in some cases, the DevTools panel (and the tree/list inside of it) has an initial height of 0 or something?

Yeah, I think for sure this is what's happening. AutoSizer bails out rendering its children when it has a height of 0:
https://github.com/bvaughn/react-virtualized-auto-sizer/blob/ffcba2dd39b89111ed4b42d64431f35ce7c1c23a/src/index.js#L121-L150

So what's happening is that the effect that should trigger the scroll gets run:

// Make sure a newly selected element is visible in the list.
// This is helpful for things like the owners list and search.
useLayoutEffect(() => {
if (selectedElementIndex !== null && listRef.current != null) {
listRef.current.scrollToItem(selectedElementIndex, 'smart');
// Note this autoscroll only works for rows.
// There's another autoscroll inside the elements
// that ensures the component name is visible horizontally.
// It's too early to do it now because the row might not exist yet.
}
}, [listRef, selectedElementIndex]);

But at that time, the list ref is null. Once it's later set, the effect doesn't get re-run, because it's a ref.

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

I think the fix to this would just be to set a min-height for the wrapper component to ensure that the AutoSizer bailout never happens in this case.

Alternately I guess I could go with a callback ref for this. Maybe that's a less hacky way to do this.

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

Based on my own testing, with a more contrived scenario, this fixes the issue. Hopefully it will fix it for you too but if not we'll revisit. For now I'll land a fix and see if you can confirm :)

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

Fixed via 8fa608d~

from react-devtools-experimental.

Daniel15 avatar Daniel15 commented on May 20, 2024

Thanks for looking into it!! :D

Will our internal FB version auto-update or do I need to manually install the update?

from react-devtools-experimental.

bvaughn avatar bvaughn commented on May 20, 2024

Will our internal FB version auto-update

Yes, assuming you've got the Chef-installed version (by being a member in the v4 Workplace group). If you've manually installed though, you'll need to manually update

from react-devtools-experimental.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.