Closed joshblack closed 2 years ago
Recipes
// TEMPLATE
function ComponentName(props, ref) {}
const ComponentName = React.forwardRef(
function ComponentName(props, ref) {}
);
ComponentName.propTypes = {};
render()
method and paste it into your new componentpropTypes
and paste them into your new componentReact.useState
from the constructor
this.*
to local variables)Special cases
React.useRef
)getDerivedStateFromProps
Situations where we would not want to migrate
componentDidCatch
has no hooks equivalentHow to use in monorepo
next
folder in the component folder that you're migrating
src/components/Notification/next/*
import * as FeatureFlags from '@carbon/feature-flags';
import { OverflowMenu as OverflowMenuNext } from './next/OverflowMenu';
import OverflowMenuClassic from './OverflowMenu';
export const OverflowMenu = FeatureFlags.enabled('enable-v11-release')
? OverflowMenuNext
: OverflowMenuClassic;
example for how to handle getDerivedStateFromProps
function TestComponent({ example }) {
const [value, setValue] = useState(example);
useEffect(() => {
setValue(example);
}, [example]);
}
becomes
function TestComponent({ example }) {
const [value, setValue] = useState(example);
const [prevExample, setPrevExample] = useState(example);
if (example !== prevExample) {
setValue(example);
setPrevExample(example);
}
}
Another thing to note on default vs named exports - the src/index.js
is typically expecting a default export. So if you're going to do a conditional export, it might be easiest to ensure it's default exports all the way through the export chain.
For instance:
// MyFunComponent/next/MyFunComponent.js
export default function MyFunComponent({...props}) {
return (
<div>{...props}</div>
);
}
// MyFunComponent/index.js
import { default as MyFunComponentNext } from './next/MyFunComponent';
import { default as MyFunComponentClassic } from './MyFunComponent';
export default MyFunComponent = FeatureFlags.enabled('enable-v11-release') ? MyFunComponentNext : MyFunComponentClassic;
We also need to add a new test file in the /next
folder for each component and update the test to pull in the v11 component.
[ ] create new Component-test.js
in Component/next
[ ] Import v11 component from ./next
[ ] re-write tests to use RTL
Here's an example done in Notification
: https://github.com/carbon-design-system/carbon/pull/9494/files
Here's an RTL example for v11 Tabs
and Tab
: https://github.com/carbon-design-system/carbon/pull/9722/files
We decided that we weren't going to test specifically for classNames being added or removed, but rather just js functionality (selection change, keyboard, click, default states, props, etc) bc VRT should cover that classNames are working as expected
These are some helpful docs:
Checklist
src/components/{component}/next/
foldersrc/components/{component/next/{component}.js
filesrc/components/{component/next/__tests__
folder and copy over teststhis
(like event handlers or refs)src/componenots/{component}/index.js
to use conditional exportspackages/react
)packages/carbon-react
)classnames
-> cx
other
-> rest
v11-carbon-components-react.md
fileQuestions
I can take over the task for the component:
Awesome! Thanks @motou we appreciate the contribution! I'll assign it to you. If you have any questions about the implementation, feel free to look at the other PRs we've opened so far, or ask questions here. 😄
@jnm2377 would you please approve the running workflows for https://github.com/carbon-design-system/carbon/pull/9955? Thanks!
@joshblack
Checklist
- [ ] Add an overview of these changes to the
v11-carbon-components-react.md
file
the right file path is docs/migration/11.x-carbon-components-react.md
Moreover, I can work on the following components:
[ ] src/components/ProgressIndicator/ProgressIndicator.js ✴️ ProgressIndicator
[ ] src/components/OverflowMenuItem/OverflowMenuItem.js ✴️ OverflowMenuItem
[ ] src/components/InlineCheckbox/InlineCheckbox.js ✴️ InlineCheckbox
Priority of these can be divided into three sections:
Looks like this can be marked as complete based on status of https://github.com/carbon-design-system/carbon/issues/10281 👍
Why are we doing this?
According to the React team, switching a component from a class component to a functional component is technically a breaking change. This is because class components accept a
ref
that points to the class instance by default. There is no way to opt-out of this behavior. As a result, if we switched a component to a functional component it would no longer have aref
, and existing code that uses aref
would break. Similarly, usingReact.forwardRef
would produce a component where theref
would no longer point to a class instance and code could similarly break.We have moved some components over to the new format despite these situations. The rationale at the time was that we weren't intending people to use these parts of a component (specifically class instance methods) and if teams were trying to use the
ref
to find a node in the document their code would work if we usedReact.forwardRef
.With v11, it seemed like a great opportunity to convert our remaining class components to the new functional component style with hooks.
Effort size legend ❇️ - sm ✴️ - md 🆘 - lg
Tasks
We would like to convert the following components to functional components that use hooks where appropriate:
src/components/ToggleSmall/ToggleSmall.Skeleton.js(this component is deprecated)ToggleSmallSkeletonsrc/components/Toggle/Toggle.Skeleton.js(this component is deprecated)ToggleSkeletonsrc/components/Tooltip/Tooltip.jsTooltip(component is being replaced in another update)src/internal/FloatingMenu.jsFloatingMenu(component will be replaced by popover)src/components/ToolbarSearch/ToolbarSearch.jsToolbarSearchsrc/components/Toggle/Toggle.jsToggle(already covered in Toggle/next)src/components/SearchLayoutButton/SearchLayoutButton.jsSearchLayoutButton(component has been deprecated)src/internal/Selection.jsSelection(will be unnecessary after moving listbox components touseSelection
)src/components/ModalWrapper/ModalWrapper.jsModalWrapper(component is deprecated)src/components/ErrorBoundary/ErrorBoundary.jsErrorBoundary(has no hooks equivalent)src/components/DataTable/DataTable.jsDataTable(too big to migrate, may use hook format in the future)src/components/ContentSwitcher/ContentSwitcher.jsContentSwitcher(currently being updated separately)