Skip to content

AppBarButton's aren't correctly re-rendered when the underlying CommandBar isn't rerendered #111

@dstaley

Description

@dstaley

When React attempts to update the AppBarButton's of a CommandBar when the underlying CommandBar isn't marked for changes, the buttons aren't rerendered, becoming out-of-sync with the React VDOM.

image

(One interesting note from this screenshot: the AppBarButtons are missing children elements after React tries to update them. Normally, they'd have a Root Grid containing a Border and Grid element, the latter of which contains a Viewbox and TextBlock.)

In this example, the <Actions /> component pulls data from a Context provider to determine what AppBarButtons to render. Since CommandBar isn't listening to that context, it doesn't need to rerender on context changes, but <Actions /> does.

import React, {useContext} from 'react';
import {
  CommandBar as XAMLCommandBar,
  CommandBarDefaultLabelPosition,
  VerticalAlignment,
  StackPanel,
  Orientation,
  Button,
  FontIcon,
  TextBlock,
  TextLineBounds,
  AppBarButton,
} from 'react-native-xaml';
import {RouterContext} from './router';
import {ToolbarContext} from './Toolbar';

const BackButton = () => {
  const {canGoBack, goBack} = useContext(RouterContext);
  return (
    <Button
      resources={{
        ButtonBackground: 'Transparent',
        ButtonBackgroundDisabled: 'Transparent',
        ButtonBorderBrushDisabled: 'Transparent',
      }}
      borderBrush="transparent"
      isEnabled={canGoBack}
      onClick={goBack}>
      <FontIcon
        fontFamily="Segoe Fluent Icons"
        glyph="&#xE72B;"
        fontSize={16}
      />
    </Button>
  );
};

const Title = () => {
  const {title} = useContext(ToolbarContext);
  return (
    <TextBlock
      verticalAlignment={VerticalAlignment.Center}
      text={title}
      fontSize={20}
      fontWeight={700}
      textLineBounds={TextLineBounds.Tight}
    />
  );
};

const Actions = () => {
  const {actions} = useContext(ToolbarContext);
  return (
    <>
      {actions.map(action => (
        <AppBarButton
          key={action.title}
          label={action.title}
          onClick={action.onClick}
          isEnabled={!action.disabled}>
          <FontIcon fontFamily="Segoe Fluent Icons" glyph={action.icon} />
        </AppBarButton>
      ))}
    </>
  );
};

export const CommandBar = () => {
  return (
    <XAMLCommandBar
      isOpen={false}
      defaultLabelPosition={CommandBarDefaultLabelPosition.Right}
      verticalContentAlignment={VerticalAlignment.Center}>
      <StackPanel
        orientation={Orientation.Horizontal}
        verticalAlignment={VerticalAlignment.Center}>
        <BackButton />
        <Title />
      </StackPanel>
      <Actions />
    </XAMLCommandBar>
  );
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions