Skip to content

SPFx Command Set - React 17 / ReactDOM - Intermittent #321 Error #9984

@chrisredman01

Description

@chrisredman01

Target SharePoint environment

SharePoint Online

What SharePoint development model, framework, SDK or API is this about?

💥 SharePoint Framework

Developer environment

Windows

What browser(s) / client(s) have you tested

  • 💥 Internet Explorer
  • 💥 Microsoft Edge
  • 💥 Google Chrome
  • 💥 FireFox
  • 💥 Safari
  • mobile (iOS/iPadOS)
  • mobile (Android)
  • not applicable
  • other (enter in the "Additional environment details" area below)

Additional environment details

  • browser version: Chrome 130.0.6723.59
  • SPFx version: 1.20.0
  • Node.js version: v18.20.4

Describe the bug / error

We are experiencing an issue similar to #9640, in which we have a Command Set button that renders a Panel component using ReactDOM.render(...) when clicked. Occasionally this errors and the console has the #321 React error.

The issue is not specific to the Panel component. Fully removing the Fluent UI React package and rendering a component that outputs a plain div which also uses hooks e.g. useEffect will get the same intermittent error.

image

After a page refresh, it works again.

The intermittent nature makes this difficult to fully confirm, but these are the current findings:

  • If the rendered component(s) don't use hooks, it works ok
  • If we drop the React version to 16.13.1, it works ok
  • If we drop the SPFx version e.g. down to 1.18.0, it still errors when using React 17

Example code:

Command Set configured to attached to Lists and Libraries

import {
  BaseListViewCommandSet,
  type Command,
  type IListViewCommandSetExecuteEventParameters,
} from "@microsoft/sp-listview-extensibility";
import * as React from "react";
import * as ReactDOM from "react-dom";
import CommandPanel from "./components/CommandPanel";

export default class ArchiveCommandSet extends BaseListViewCommandSet<IArchiveCommandSetProperties> {
  private _panelPlaceHolder: HTMLDivElement;

  public onInit(): Promise<void> {
    this._panelPlaceHolder = document.body.appendChild(
      document.createElement("div")
    );

    const archiveCommand: Command = this.tryGetCommand("COMMAND_ARCHIVE");
    archiveCommand.visible = true;

    return Promise.resolve();
  }

  public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
    switch (event.itemId) {
      case "COMMAND_ARCHIVE":
        this._renderPanelComponent();
        break;
      default:
        throw new Error("Unknown command");
    }
  }

  public onDispose(): void {
    ReactDOM.unmountComponentAtNode(this._panelPlaceHolder);
  }

  private _renderPanelComponent = (): void => {
    const element: React.ReactElement = React.createElement(CommandPanel);
    ReactDOM.render(element, this._panelPlaceHolder);
  };
}

Failing Component:

import * as React from "react";

const CommandPanel: React.FunctionComponent = () => {
  React.useEffect(() => { console.log("hello"); }, []);

  return (
    <div
      style={{
        position: "absolute",
        top: "20%",
        left: "40%",
        backgroundColor: "red",
        fontSize: "18px",
        padding: "2em 1em",
        zIndex: 99999,
      }}
    >
      hello world!
    </div>
  );
};

export default CommandPanel;

package.json

{
  "name": "test",
  "version": "0.0.1",
  "private": true,
  "engines": {
    "node": ">=18.17.1 <19.0.0"
  },
  "main": "lib/index.js",
  "scripts": {
    "build": "gulp bundle",
    "clean": "gulp clean",
    "test": "gulp test"
  },
  "dependencies": {
    "@microsoft/decorators": "1.20.0",
    "@microsoft/sp-core-library": "1.20.0",
    "@microsoft/sp-dialog": "1.20.0",
    "@microsoft/sp-listview-extensibility": "1.20.0",
    "@microsoft/sp-lodash-subset": "1.20.0",
    "@microsoft/sp-office-ui-fabric-core": "1.20.0",
    "@microsoft/sp-property-pane": "1.20.0",
    "@microsoft/sp-webpart-base": "1.20.0",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "tslib": "2.3.1"
  },
  "devDependencies": {
    "@microsoft/eslint-config-spfx": "1.20.2",
    "@microsoft/eslint-plugin-spfx": "1.20.2",
    "@microsoft/rush-stack-compiler-4.7": "0.1.0",
    "@microsoft/sp-build-web": "1.20.2",
    "@microsoft/sp-module-interfaces": "1.20.2",
    "@rushstack/eslint-config": "4.0.1",
    "@types/webpack-env": "~1.15.2",
    "ajv": "^6.12.5",
    "eslint": "8.57.0",
    "gulp": "4.0.2",
    "typescript": "4.7.4"
  }
}

Steps to reproduce

From what we can determine, it happens (intermittently) with the following steps:

  • Open a fresh browser session
  • Navigate to the SharePoint library
  • Refresh the page (this seems to be the key step)
  • Click the Command Set button
  • Sometimes results in the React 321 error

From our testing, it seems to be the refresh step which then results in the behaviour happening. Without the refresh, we've not been able to reproduce it - but as it's intermittent, that's hard to say for certain!

However...when in the failed state, a page refresh then resolves it.

Expected behavior

For the component rendered via ReactDOM.render(...) to work consistently.

Metadata

Metadata

Assignees

Labels

Needs: Triage 🔍Awaiting categorization and initial review.type:bug-suspectedSuspected bug (not working as designed/expected). See “type:bug-confirmed” for confirmed bugs.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions