Skip to content

MM-69835 Replace legacy context API with modern one - #9

Open
hmhealey wants to merge 1 commit into
MM-69835-1from
MM-69835-2
Open

MM-69835 Replace legacy context API with modern one#9
hmhealey wants to merge 1 commit into
MM-69835-1from
MM-69835-2

Conversation

@hmhealey

@hmhealey hmhealey commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

The next part of updating this for React 19 is to get rid of all usage of the now-deprecated legacy context API. Instead of using contextTypes/childContextTypes/getChildContext, we now use React.createContext to make provider components along with useContext in function components and the slightly different contextType in class components.

Ticket Link

https://mattermost.atlassian.net/browse/MM-69835

@hmhealey hmhealey changed the title Replace legacy context API with modern one MM-69835 Replace legacy context API with modern one Aug 4, 2026
@hmhealey

hmhealey commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai Review this

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

@hmhealey I will review pull request #9.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces legacy React context declarations and child-context methods with named context objects, providers, contextType, and useContext across form, modal, navbar, panel, and tab components. Test warning suppression and legacy test context setup were also removed.

Changes

React context migration

Layer / File(s) Summary
Form and modal context migration
src/FormGroup.js, src/FormGroupContext.js, src/ControlLabel.js, src/FormControl.js, src/FormControlFeedback.js, src/Modal.js, src/ModalContext.js, src/ModalHeader.js, test/*
Form groups and modals now provide named React context values. Descendant components consume direct context values through contextType.
Navbar and navigation context migration
src/Navbar.js, src/NavbarContext.js, src/NavbarBrand.js, src/NavbarCollapse.js, src/NavbarHeader.js, src/NavbarToggle.js, src/Nav.js
Navbar state now uses NavbarContext. Nav receives navbar and tab-container context through a useContext wrapper.
Panel group and panel context migration
src/PanelGroup.js, src/PanelGroupContext.js, src/Panel.js, src/PanelContext.js, src/PanelBody.js, src/PanelCollapse.js, src/PanelFooter.js, src/PanelHeading.js, src/PanelTitle.js, src/PanelToggle.js
Panel groups and panels now provide explicit context values. Panel descendants consume direct panel context values.
Tab container and pane context migration
src/TabContainer.js, src/TabContainerContext.js, src/TabContent.js, src/TabContentContext.js, src/TabPane.js
Tab selection, identifiers, content state, and pane rendering now use modern React context providers and consumers.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: replacing the legacy React context API with the modern context API.
Description check ✅ Passed The description directly explains the migration from the legacy context API to React's modern context features.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MM-69835-2

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Nav.js`:
- Around line 347-360: Wrap NavWithContext with React forwardRef, update its
signature to receive the forwarded ref, and pass ref={ref} to the inner Nav
component. Preserve the existing context retrieval, props spreading, and bsClass
export behavior.

In `@src/Panel.js`:
- Around line 87-100: Update the ID-generation guard in the Panel logic around
eventKey, id, and idKey so generation runs only when an identifier is actually
present, including excluding undefined. Preserve the existing getId selection
and headingId/bodyId creation for valid identifiers, while leaving ids unset
when both props are absent.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8581677c-27e0-4822-a61f-75edf7ca6701

📥 Commits

Reviewing files that changed from the base of the PR and between e909302 and b5d10b9.

📒 Files selected for processing (32)
  • src/ControlLabel.js
  • src/FormControl.js
  • src/FormControlFeedback.js
  • src/FormGroup.js
  • src/FormGroupContext.js
  • src/Modal.js
  • src/ModalContext.js
  • src/ModalHeader.js
  • src/Nav.js
  • src/Navbar.js
  • src/NavbarBrand.js
  • src/NavbarCollapse.js
  • src/NavbarContext.js
  • src/NavbarHeader.js
  • src/NavbarToggle.js
  • src/Panel.js
  • src/PanelBody.js
  • src/PanelCollapse.js
  • src/PanelContext.js
  • src/PanelFooter.js
  • src/PanelGroup.js
  • src/PanelGroupContext.js
  • src/PanelHeading.js
  • src/PanelTitle.js
  • src/PanelToggle.js
  • src/TabContainer.js
  • src/TabContainerContext.js
  • src/TabContent.js
  • src/TabContentContext.js
  • src/TabPane.js
  • test/OverlayTriggerSpec.js
  • test/index.js
💤 Files with no reviewable changes (2)
  • test/OverlayTriggerSpec.js
  • test/index.js

Comment thread src/Nav.js
Comment on lines +347 to +360
function NavWithContext(props) {
const navbarContext = useContext(NavbarContext);
const tabContainerContext = useContext(TabContainerContext);

return (
<Nav
{...props}
navbarContext={navbarContext}
tabContainerContext={tabContainerContext}
/>
);
}

export default bsClass('nav', bsStyles(['tabs', 'pills'], NavWithContext));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find in-repository consumers that attach refs to Nav.
rg -nP --glob '*.{js,jsx,ts,tsx}' '<Nav\b[^>]*\bref\s*=' . || true

# Confirm that the public wrapper forwards the ref to the class component.
rg -n -C 4 'NavWithContext|forwardRef|<Nav' src/Nav.js

Repository: mattermost/react-bootstrap

Length of output: 1897


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Nav.js imports and class definition ---'
sed -n '1,80p' src/Nav.js
sed -n '80,180p' src/Nav.js
sed -n '330,365p' src/Nav.js

printf '%s\n' '--- package versions and wrapper implementation ---'
rg -n '"react"|"react-dom"|"react-bootstrap"|bsClass|function bsClass|const bsClass|export default' package.json src utils 2>/dev/null || true
fd -t f -i 'bootstrapUtils|bsClass|createChainedFunction' .

Repository: mattermost/react-bootstrap

Length of output: 21849


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- bootstrapUtils wrapper implementation ---'
sed -n '1,175p' src/utils/bootstrapUtils.js

printf '%s\n' '--- package metadata and React support ---'
sed -n '1,125p' package.json

printf '%s\n' '--- Nav ref usage in tests and source ---'
rg -n -i 'ref|findDOMNode|Nav' test/Nav* test src --glob '*.{js,jsx,ts,tsx}' | head -n 240

Repository: mattermost/react-bootstrap

Length of output: 23497


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Nav.js change context ---'
git diff -- src/Nav.js

printf '%s\n' '--- Read-only structural verifier ---'
python3 - <<'PY'
from pathlib import Path
import re

nav = Path('src/Nav.js').read_text()
utils = Path('src/utils/bootstrapUtils.js').read_text()

assert re.search(r'function NavWithContext\s*\(\s*props\s*\)', nav), \
    'NavWithContext is not currently a props-only function'
assert not re.search(r'\bforwardRef\b', nav), \
    'Nav.js already forwards refs'
assert re.search(
    r'return\s+Component\s*;',
    utils
), 'bsClass does not visibly return the component'
assert re.search(
    r'export default bsClass\([^\n]*NavWithContext\)',
    nav
), 'NavWithContext is not the exported component'

print('NavWithContext accepts only props and does not use forwardRef.')
print('bsClass returns the component it decorates, so it does not add a ref boundary.')
print('The exported Nav component therefore does not forward refs to the inner Nav class.')
PY

Repository: mattermost/react-bootstrap

Length of output: 457


Forward refs through NavWithContext.

Wrap NavWithContext with forwardRef and pass ref={ref} to <Nav>. The current exported component does not expose the inner Nav instance to React 18 consumers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Nav.js` around lines 347 - 360, Wrap NavWithContext with React
forwardRef, update its signature to receive the forwarded ref, and pass
ref={ref} to the inner Nav component. Preserve the existing context retrieval,
props spreading, and bsClass export behavior.

Comment thread src/Panel.js
Comment on lines +87 to +100
const { eventKey, id } = this.props;
const idKey = eventKey == null ? id : eventKey;

let ids;

if (idKey !== null) {
const panelGroup = this.context;
const getId = (panelGroup && panelGroup.getId) || defaultGetId;

ids = {
headingId: getId(idKey, 'heading'),
bodyId: getId(idKey, 'body')
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Skip ID generation when the panel has no identifier.

When both eventKey and id are absent, idKey is undefined, so idKey !== null is true. A custom generateChildId then receives undefined. Multiple panels can receive the same heading and body IDs. This breaks the related ARIA references.

Proposed fix
-    if (idKey !== null) {
+    if (idKey != null) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { eventKey, id } = this.props;
const idKey = eventKey == null ? id : eventKey;
let ids;
if (idKey !== null) {
const panelGroup = this.context;
const getId = (panelGroup && panelGroup.getId) || defaultGetId;
ids = {
headingId: getId(idKey, 'heading'),
bodyId: getId(idKey, 'body')
};
}
const { eventKey, id } = this.props;
const idKey = eventKey == null ? id : eventKey;
let ids;
if (idKey != null) {
const panelGroup = this.context;
const getId = (panelGroup && panelGroup.getId) || defaultGetId;
ids = {
headingId: getId(idKey, 'heading'),
bodyId: getId(idKey, 'body')
};
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Panel.js` around lines 87 - 100, Update the ID-generation guard in the
Panel logic around eventKey, id, and idKey so generation runs only when an
identifier is actually present, including excluding undefined. Preserve the
existing getId selection and headingId/bodyId creation for valid identifiers,
while leaving ids unset when both props are absent.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant