mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-11 18:55:55 +00:00
- Adds React 18 and 19 migration orchestration plugins - Introduces comprehensive upgrade toolkits for migrating legacy React 16/17 and 18 codebases to React 18.3.1 and 19, respectively. Each plugin bundles specialized agents and skills for exhaustive audit, dependency management, class/component API migration, test suite transformation, and batching regression fixes. - The React 18 toolkit targets class-component-heavy apps, ensures safe lifecycle and context transitions, resolves dependency blockers, and fully automates test migrations including Enzyme removal. The React 19 toolkit addresses breaking changes such as removal of legacy APIs, defaultProps on function components, and forwardRef, while enforcing a gated, memory-resumable migration pipeline. - Both plugins update documentation, plugin registries, and skill references to support reliable, repeatable enterprise-scale React migrations.
225 lines
5.1 KiB
Markdown
225 lines
5.1 KiB
Markdown
# Single Context Migration - Complete Before/After
|
|
|
|
## Full Example: ThemeContext
|
|
|
|
This covers the most common pattern - one context with one provider and multiple consumers.
|
|
|
|
---
|
|
|
|
### Step 1 - Before State (Legacy)
|
|
|
|
**ThemeProvider.js (provider):**
|
|
|
|
```jsx
|
|
import PropTypes from 'prop-types';
|
|
|
|
class ThemeProvider extends React.Component {
|
|
static childContextTypes = {
|
|
theme: PropTypes.string,
|
|
toggleTheme: PropTypes.func,
|
|
};
|
|
|
|
state = { theme: 'light' };
|
|
|
|
toggleTheme = () => {
|
|
this.setState(s => ({ theme: s.theme === 'light' ? 'dark' : 'light' }));
|
|
};
|
|
|
|
getChildContext() {
|
|
return {
|
|
theme: this.state.theme,
|
|
toggleTheme: this.toggleTheme,
|
|
};
|
|
}
|
|
|
|
render() {
|
|
return this.props.children;
|
|
}
|
|
}
|
|
```
|
|
|
|
**ThemedButton.js (class consumer):**
|
|
|
|
```jsx
|
|
import PropTypes from 'prop-types';
|
|
|
|
class ThemedButton extends React.Component {
|
|
static contextTypes = {
|
|
theme: PropTypes.string,
|
|
toggleTheme: PropTypes.func,
|
|
};
|
|
|
|
render() {
|
|
const { theme, toggleTheme } = this.context;
|
|
return (
|
|
<button className={`btn btn-${theme}`} onClick={toggleTheme}>
|
|
Toggle Theme
|
|
</button>
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
**ThemedHeader.js (function consumer - if any):**
|
|
|
|
```jsx
|
|
// Function components couldn't use legacy context cleanly
|
|
// They had to use a class wrapper or render prop
|
|
```
|
|
|
|
---
|
|
|
|
### Step 2 - Create Context File
|
|
|
|
**src/contexts/ThemeContext.js (new file):**
|
|
|
|
```jsx
|
|
import React from 'react';
|
|
|
|
// Default value matches the shape of getChildContext() return
|
|
export const ThemeContext = React.createContext({
|
|
theme: 'light',
|
|
toggleTheme: () => {},
|
|
});
|
|
|
|
// Named export for the context - both provider and consumers import from here
|
|
```
|
|
|
|
---
|
|
|
|
### Step 3 - Update Provider
|
|
|
|
**ThemeProvider.js (after):**
|
|
|
|
```jsx
|
|
import React from 'react';
|
|
import { ThemeContext } from '../contexts/ThemeContext';
|
|
|
|
class ThemeProvider extends React.Component {
|
|
state = { theme: 'light' };
|
|
|
|
toggleTheme = () => {
|
|
this.setState(s => ({ theme: s.theme === 'light' ? 'dark' : 'light' }));
|
|
};
|
|
|
|
render() {
|
|
// React 19 JSX shorthand: <ThemeContext value={...}>
|
|
// React 18: <ThemeContext.Provider value={...}>
|
|
return (
|
|
<ThemeContext.Provider
|
|
value={{
|
|
theme: this.state.theme,
|
|
toggleTheme: this.toggleTheme,
|
|
}}
|
|
>
|
|
{this.props.children}
|
|
</ThemeContext.Provider>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ThemeProvider;
|
|
```
|
|
|
|
> **React 19 note:** In React 19 you can write `<ThemeContext value={...}>` directly (no `.Provider`). For React 18.3.1 use `<ThemeContext.Provider value={...}>`.
|
|
|
|
---
|
|
|
|
### Step 4 - Update Class Consumer
|
|
|
|
**ThemedButton.js (after):**
|
|
|
|
```jsx
|
|
import React from 'react';
|
|
import { ThemeContext } from '../contexts/ThemeContext';
|
|
|
|
class ThemedButton extends React.Component {
|
|
// singular contextType (not contextTypes)
|
|
static contextType = ThemeContext;
|
|
|
|
render() {
|
|
const { theme, toggleTheme } = this.context;
|
|
return (
|
|
<button className={`btn btn-${theme}`} onClick={toggleTheme}>
|
|
Toggle Theme
|
|
</button>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ThemedButton;
|
|
```
|
|
|
|
**Key differences from legacy:**
|
|
|
|
- `static contextType` (singular) not `contextTypes` (plural)
|
|
- No PropTypes declaration needed
|
|
- `this.context` is the full value object (not a partial - whatever you passed to `value`)
|
|
- Only ONE context per class component via `contextType` - use `Context.Consumer` render prop for multiple
|
|
|
|
---
|
|
|
|
### Step 5 - Update Function Consumer
|
|
|
|
**ThemedHeader.js (after - now straightforward with hooks):**
|
|
|
|
```jsx
|
|
import { useContext } from 'react';
|
|
import { ThemeContext } from '../contexts/ThemeContext';
|
|
|
|
function ThemedHeader({ title }) {
|
|
const { theme } = useContext(ThemeContext);
|
|
return <h1 className={`header-${theme}`}>{title}</h1>;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Step 6 - Multiple Contexts in One Class Component
|
|
|
|
If a class component consumed more than one legacy context, it gets complex. Class components can only have one `static contextType`. For multiple contexts, use the render prop form:
|
|
|
|
```jsx
|
|
import { ThemeContext } from '../contexts/ThemeContext';
|
|
import { AuthContext } from '../contexts/AuthContext';
|
|
|
|
class Dashboard extends React.Component {
|
|
render() {
|
|
return (
|
|
<ThemeContext.Consumer>
|
|
{({ theme }) => (
|
|
<AuthContext.Consumer>
|
|
{({ user }) => (
|
|
<div className={`dashboard-${theme}`}>
|
|
Welcome, {user.name}
|
|
</div>
|
|
)}
|
|
</AuthContext.Consumer>
|
|
)}
|
|
</ThemeContext.Consumer>
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
Or consider migrating the class component to a function component to use `useContext` cleanly.
|
|
|
|
---
|
|
|
|
### Verification Checklist
|
|
|
|
After migrating one context:
|
|
|
|
```bash
|
|
# Provider - no legacy context exports remain
|
|
grep -n "childContextTypes\|getChildContext" src/ThemeProvider.js
|
|
|
|
# Consumers - no legacy context consumption remains
|
|
grep -rn "contextTypes\s*=" src/ --include="*.js" --include="*.jsx" | grep -v "ThemeContext\|\.test\."
|
|
|
|
# this.context usage - confirm it reads from contextType not legacy
|
|
grep -rn "this\.context\." src/ --include="*.js" | grep -v "\.test\."
|
|
```
|
|
|
|
Each should return zero hits for the migrated context.
|