palantir/blueprint

Selected Tab indicator is sometimes misaligned on page load/refresh when using React Router.

Open

#3,824 创建于 2019年11月7日

在 GitHub 查看
 (3 评论) (4 反应) (0 负责人)TypeScript (20,263 star) (2,167 fork)batch import
P3Package: coreType: bughelp wanted

描述

Environment

@blueprintjs/core 3.17.1 The problem manifests in many browser/OS combinations.

Steps to reproduce

  1. Use Tabs with Router in such a way that the route determines which tab is selected.
  2. Refresh a URL that causes a tab to be selected.
import React, { PureComponent } from 'react';
import { withRouter } from 'react-router-dom';
import { HeaderTabs, getTabId } from './our/code';

class Header extends PureComponent {

  render() {
    /* Selected tab ID is derived from the Router-supplied 'history' object */
    const tabId = getTabId( this.props.history.location.pathname );

    return (
        <div>
          <HeaderTabs tabId={tabId} />
        </div>
      );
  }
}

export default withRouter(Header);
import React, { PureComponent } from 'react';
import { Tab, Tabs } from '@blueprintjs/core';

export default class HeaderTabs extends PureComponent {

  componentDidMount() {
    /* Hack to compensate for selected tab indicator being misaligned on refresh. */
    setTimeout( () => this.forceUpdate(), 1000 );
  }

  render() {
    return (
      <div>
        <Tabs selectedTabId={ this.props.tabId } >
          { [ _array of valid tab data objects_ ].map(tabProps => (<Tab {...tabProps}/>)) }
        </Tabs>
      </div>
    );
  }
}

Actual behavior

Sometimes when the component mounts, the indicator for the selected tab will be misplaced and/or mis-sized. The degree of mis-sizing is inconsistent, and it does not always occur. (Example of misplacement below.)

This occurs only when the component mounts. Once mounted, selecting any tab will cause the indicator to position/size correctly.

We are using animated indicator.

Expected behavior

Tab indicator should always have correct size and placement.

Possible solution

This hack ameliorates the issue. Whatever component is rendering the <Tabs> is forced to update after the HTML has rendered, which causes the indicator to size correctly. (This is the same effect as clicking a tab.)

class SomethingThatUsesTabs extends PureComponent {
  componentDidMount() {
    setTimeout(() => this.forceUpdate(), 1000);
  }
  render() {
    return <Tabs ... > ... </Tabs>
  }
}

贡献者指南