MM-69835 Replace legacy context API with modern one - #9
Conversation
|
@coderabbitai Review this |
|
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughThe PR replaces legacy React context declarations and child-context methods with named context objects, providers, ChangesReact context migration
Estimated code review effort: 4 (Complex) | ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (32)
src/ControlLabel.jssrc/FormControl.jssrc/FormControlFeedback.jssrc/FormGroup.jssrc/FormGroupContext.jssrc/Modal.jssrc/ModalContext.jssrc/ModalHeader.jssrc/Nav.jssrc/Navbar.jssrc/NavbarBrand.jssrc/NavbarCollapse.jssrc/NavbarContext.jssrc/NavbarHeader.jssrc/NavbarToggle.jssrc/Panel.jssrc/PanelBody.jssrc/PanelCollapse.jssrc/PanelContext.jssrc/PanelFooter.jssrc/PanelGroup.jssrc/PanelGroupContext.jssrc/PanelHeading.jssrc/PanelTitle.jssrc/PanelToggle.jssrc/TabContainer.jssrc/TabContainerContext.jssrc/TabContent.jssrc/TabContentContext.jssrc/TabPane.jstest/OverlayTriggerSpec.jstest/index.js
💤 Files with no reviewable changes (2)
- test/OverlayTriggerSpec.js
- test/index.js
| 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)); |
There was a problem hiding this comment.
🎯 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.jsRepository: 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 240Repository: 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.')
PYRepository: 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.
| 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') | ||
| }; | ||
| } |
There was a problem hiding this comment.
🎯 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.
| 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.
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 useReact.createContextto make provider components along withuseContextin function components and the slightly differentcontextTypein class components.Ticket Link
https://mattermost.atlassian.net/browse/MM-69835