Migrating from v0 to v1
diegohaz opened this issue ยท 27 comments
Migrating from v0 to v1
I think experimentation is the only way to get things right. In v0, we've been experimenting a lot, often with approaches that were controversial by the time we came up with them. Some of them worked. Some others, not so much. I tried to keep the good things in v1, improve the things that could be improved and discard the ones that weren't good at all.
I've been working on this v1 directly since November 2018, when I started writing this gist as an attempt to come up with a hooks-only API. I even implemented an early version of this in a private project to finally realize that a hooks-only API doesn't provide much ergonomics for most developers, but it's really amazing for composability.
This is intended to be a living document. I'm going to update it over time, and I hope it's finished by the time v1 comes out of beta. If something is missing here, please comment down.
๐จ Important note ๐จ
There are many breaking changes. And I understand that people may get a little upset about it. If v0.x
is working well for you, there's no need to upgrade to v1
so soon. The same happened to Rebass and Material-UI, for example. I'll keep merging bug fixes into the v0 branch and you can keep accessing the v0 docs. Take your time and make a gradual migration only when necessary (for example, if you need some new feature that's only available in v1
).
Gradual migration
You can leverage Yarn's ability to install multiple versions of a package:
yarn add reakit-next@npm:reakit@1.0.0-beta.0
import { Provider as ReakitProvider } from "reakit"; // v0
import { Provider as NextReakitProvider } from "reakit-next"; // v1
Alternatively, if it's not enough, there may be a Reakit v0 version with a /next
path.
No styled-components
Dependency on styled-components has been removed, which means we don't re-export its members anymore. You're free to use any version of SC or another CSS library without worrying about bundle size.
Before:
import { styled, Box } from "reakit";
After:
import { Box } from "reakit";
import styled from "styled-components";
Primitives
Since the core library doesn't care about styles anymore, these styled components have been removed. They can be re-created with styled-components.
Before:
import { Block, Flex, Grid, Inline, InlineBlock, InlineFlex } from "reakit";
After:
import { Box } from "reakit";
import styled from "styled-components";
const Block = styled(Box)`display: block;`;
const Flex = styled(Box)`display: flex;`;
const Grid = styled(Box)`display: grid;`;
const Inline = styled(Box)`display: inline;`;
const InlineBlock = styled(Box)`display: inline-block;`;
const InlineFlex = styled(Box)`display: inline-flex;`;
CSS Props
Since the core library doesn't care about styles anymore, these props have been removed. You can use inline style directly.
Before:
<Box marginRight={100} color="red" />
After:
<Box style={{ marginRight: 100, color: "red" }} />
as
/use
props
In v0.16, we introduced the use
prop as a replacement to the as
prop. The main motivation behind this change was that the as
prop conflicted with the styled-components' one. And, since Reakit's one behaved differently (by accepting an array of components, for example), that made sense to rename the prop.
Now that we're not limited to styled-components anymore and this works exactly like in other libraries (accepting only one component), we're back to the as
prop for consistency.
Before:
<Hidden use="div" />
<Hidden use={Button} />
<Hidden use={[Button, "div"]} />
After:
<Hidden as="div" />
<Hidden as={Button} />
// using render props: https://reakit.io/docs/basic-concepts/#render-props
<Hidden>{props => <Button as="div" {...props} />}</Hidden>
Theming
Reakit doesn't depend on styled-components anymore. You can use Reakit v0 theme by wrapping components with your own version of styled-components.
Before:
import { Provider, Button, css } from "reakit";
const theme = {
Button: css`
color: red;
`;
};
<Provider theme={theme}>
<Button />
</Provider>
After:
import { Button as ReakitButton } from "reakit";
import { ThemeProvider, styled, css } from "styled-components";
const theme = {
Button: css`
color: red;
`;
};
const Button = styled(ReakitButton)(props => props.theme.Button);
<ThemeProvider theme={theme}>
<Button />
</ThemeProvider>
Hidden
Hidden.Container
has been replaced by the useHiddenState
hook. Hidden.Show
, Hidden.Hide
and Hidden.Toggle
have been removed. HiddenDisclosure
can be used instead.
Before:
import { Hidden } from "reakit";
function MyHidden() {
return (
<Hidden.Container>
{hidden => (
<>
<Hidden.Show {...hidden}>Show</Hidden.Show>
<Hidden.Hide {...hidden}>Hide</Hidden.Hide>
<Hidden.Toggle {...hidden}>Toggle</Hidden.Toggle>
<Hidden {...hidden}>Hidden</Hidden>
</>
)}
</Hidden.Container>
);
}
After:
import { useHiddenState, Hidden, HiddenDisclosure } from "reakit";
function MyHidden() {
const hidden = useHiddenState();
return (
<>
<button onClick={hidden.show}>Show</button>
<button onClick={hidden.hide}>Hide</button>
<HiddenDisclosure {...hidden}>Toggle</HiddenDisclosure>
<Hidden {...hidden}>Hidden</Hidden>
</>
);
}
Overlay
Overlay
has been replaced by Dialog
.
Before:
import { Overlay, Backdrop } from "reakit";
function MyOverlay() {
return (
<Overlay.Container>
{overlay => (
<>
<Overlay.Show {...overlay}>Click me</Overlay.Show>
<Backdrop use={Overlay.Hide} {...overlay} />
<Overlay {...overlay}>Overlay</Overlay>
</>
)}
</Overlay.Container>
);
}
After:
import { useDialogState, Dialog, DialogDisclosure, DialogBackdrop } from "reakit";
function MyOverlay() {
const dialog = useDialogState();
return (
<>
<DialogDisclosure {...dialog}>Click me</DialogDisclosure>
<DialogBackdrop {...dialog} />
<Dialog {...dialog} aria-label="My overlay">Dialog</Dialog>
</>
);
}
Popover
TODO
Sidebar
Before:
import { Button, Backdrop, Sidebar } from "reakit";
function MySidebar() {
return (
<Sidebar.Container>
{sidebar => (
<>
<Button use={Sidebar.Show} {...sidebar}>
Open sidebar
</Button>
<Backdrop use={Sidebar.Hide} {...sidebar} />
<Sidebar {...sidebar}>Sidebar</Sidebar>
</>
)}
</Sidebar.Container>
);
}
After:
import { useDialogState, Dialog, DialogDisclosure, DialogBackdrop } from "reakit";
import styled from "styled-components";
const Sidebar = styled(Dialog)`
position: fixed;
top: 0;
left: 0;
height: 100vh;
overflow: auto;
`;
function MySidebar() {
const dialog = useDialogState();
return (
<>
<DialogDisclosure {...dialog}>Open sidebar</DialogDisclosure>
<DialogBackdrop {...dialog} />
<Sidebar {...dialog}>Sidebar</Sidebar>
</>
);
}
Step
If people find it useful, it's possible to have this component in Reakit again in v1. In the meanwhile, it can be re-created with Hidden
and useRoverState
.
Before:
import { Step, Button } from "reakit";
function MyStep() {
return (
<Step.Container initialState={{ current: 0 }}>
{step => (
<>
<Button use={Step.Previous} {...step}>Previous</Button>
<Button use={Step.Next} {...step}>Next</Button>
<Step step="Step 1" {...step}>Step 1</Step>
<Step step="Step 2" {...step}>Step 2</Step>
<Step step="Step 3" {...step}>Step 3</Step>
</>
)}
</Step.Container>
);
}
After:
import { useRoverState, Hidden } from "reakit";
function Step(props) {
const ref = React.useRef();
React.useEffect(() => {
props.register(props.step, ref);
return () => props.unregister(props.step);
}, [props.register, props.unregister, props.step]);
return (
<Hidden
ref={ref}
visible={props.step === props.currentId}
{...props}
/>
);
}
function MyStep() {
const rover = useRoverState({ currentId: "step1" });
return (
<>
<button onClick={rover.previous}>Previous</button>
<button onClick={rover.next}>Next</button>
<Step step="step1" {...rover}>Step 1</Step>
<Step step="step2" {...rover}>Step 2</Step>
<Step step="step3" {...rover}>Step 3</Step>
</>
);
}
Tabs
TODO
Toolbar
TODO
Tooltip
TODO
Backdrop
TODO
Button
TODO
Divider
It has been replaced by Separator
to match the WAI-ARIA role.
Before:
import { Divider } from "reakit";
<Divider vertical />
After:
import { Separator } from "reakit";
<Separator orientation="vertical" />
Half of all components since 0.16.0 seem to be gone (Grid, Image, Flex etc).
When I try the Box component, the CSS props functionality (marginRight={100}) as well seem to be gone.
I absolutely love experimentation as well. I do it daily. You're doing an amazing job with all libraries out there, but just want to let you know that this is (for me) mostly a completely new library from an API point of view.
Any suggestion how to mitigate the situation when heavily dependent on the components/functionality prior to 1.0?
@axhamre I'm sorry about that. This is not a different library. It's just more focused.
The components that have been removed were pretty minimal. They can be easily implemented in the user land. I've written a simple guide to CSS props. Please, tell me if you need more details on that.
Also, please list the components you rely on the most so I can prioritize them for the guide (same for anyone reading this).
Jesus Christ, I just migrated from 0.15 to 0.16 (with lots of breaking changes, such as the use=""
instead of as=""
) and now I see that as
is back and most of the components written with reakit need to be basically re-written. Absolutely crazy!!!!!!! Why would you remove Flex
and Grid
as they were immensely useful alongside with casually dropping a backgroundColor=""
when you needed it, instead of creating a style for that? You say you are more focused. Fine, but I am not sure you have asked your users enough what they liked about Reakit and what they used it for. Very disappointed fan here!
@paulbalogh Reading your comment makes me sad as I've worked hard to make this release the best for everyone.
Fine, but I am not sure you have asked your users enough what they liked about Reakit and what they used it for.
I did, but I don't see your feedback on #261 or #288 or #345 or here. I can't find you on any of our communities so I could've asked privately as I did with some people. I can't find your email listed in our mailing list so I could tell you about the v1.0.0-alpha
release more than a month ago. I've been tweeting about this release since v0.16.0
got released. Where were you? If you care that much, why didn't you get involved?
Regardless, if a version is working well for you, why do you need to upgrade it? Why not just stick with 0.16
? I'll keep merging bug fixes into the v0 branch. If you need features that are only available in v1
, you can use the technique described in the Gradual migration section and import only that component.
That said, most of the things that changed can be re-created in just one file (for everything). List the components you rely on the most, and I do my best to provide a comprehensive guide for them.
Reakit has a codemod which was used in order to ease the transition from 0.15 to 0.16 (https://www.npmjs.com/package/reakit-codemods). We all provided ways to make users life easy, to make it reasonable to use. This library also followed semver strictly, where prior v1, everything can be considered as a breaking change.
@diegohaz - look, I probably need to apologise, these rants are not constructive especially when we are talking about a free library, maintained by the hard work of many people (btw, we are not only consuming, we are also contributing back, one of the members of our team is among your contributors). I have not seen the discussion threads you mention, even though I used reakit daily and I used the docs all the time to check the APIs I need. I have not seen any information on the upcoming v1. Took me entirely
by surprise. Hence my shock last night on discovering the new version. (btw: neither the website nor the readme on git say anything about the current version or that v1 is still beta).
That being said, I only want to add this: the migration seems a massive pain. Especially if you don't have a big frontend team behind. We are a startup that switched from Semantic UI to reakit and loved what we found. I not sure now how or whether we will switch to v1. That is the only message I have. We may not be the only other user contemplating these choices.
Comment that its pretty much a new library is a valid one; I'm in production and needed changes for upgrade are pretty huge. Especially when some of the components are plain missing in the new version. Ie, Sidebar is not a one liner userland fix.
Having said that, @diegohaz its perfectly fine you're driving this in direction you see best, but please pin a link for documentation of the 0.x version somewhere visible. This isnt an overnight change for users of your lib, and we still need an old docs.
Added examples on Sidebar
and made v0 references on README more evident. There's no final API for animations/transitions in v1 yet. There's an unstable_animated
prop, but it's likely to change (hence the unstable_
prefix).
Please, keep listing the things so I can prioritize them on the guide.
Please, keep listing the things so I can prioritize them on the guide.
Thank you. I would, but we're using pretty much every single thing on that list :) So take your time in this, we'll have to stick to 0.x until we have a clear upgrade plan and some cycles to actually do it.
Started upgrading to the beta today and hopefully will have most done by the end of the weekend.
Since my site is currently in a complete client-side rewrite I will go through everything. No gradual migration, going straight on the new version and dealing with what comes my way. ๐
So far I'm missing from this guide components like Paragraph
, Heading
, Image
(probably only needs a short mention) and themes.
@StorytellerCZ Could you describe a bit how you used the themes? There are many ways to approach this, but I believe the most straight forward is to just use styled-components + styled-tools directly (if you're using styled-components).
I'm gonna update the post with this soon.
@paulbalogh You can install from a specific version and remove ^
from your package.json
@diegohaz Yes, I'm using styled-components with styled-tools. If I remember corectly I'm using the same approach as the old Reakit docs.
Missing:
Divider
=> Separator
Before
import { Divider } from 'reakit';
<Divider vertical />
After
import { Separator } from 'reakit';
<Separator orientation="vertical" />
Added Divider
. Thank you @StorytellerCZ
@diegohaz Thank you for all your hard work on the v1 of reakit! I'm loving the direction of v1 so far. I was wondering if you had any advice for Input
since it is no longer provided? Should I just do
const Input = styled.input` /* styles here */ `
Hey @stramel. We have plans to provide an abstract Input
component in the future (once v1 gets out of beta, where we're focusing more on fixing bugs).
In the meanwhile, I suggest you to look at the code from v0:
reakit-theme-default
:
https://github.com/reakit/reakit/blob/fd10c8bd0c55f04a36c3b8f7d949c181a8b30d96/packages/reakit-theme-default/src/index.ts#L201-L225
Hello! I'm following the migration guide and installing reakit@1.0.0-beta5
as reakit-next
. I'm running into the following issue:
TypeScript error in /Users/andresrodriguez/CFS/roadside-app/node_modules/reakit-system/src/createComponent.ts(3,30):
Cannot find module 'reakit/Box/Box'. TS2307
1 | // TODO: Refactor
2 | import * as React from "react";
> 3 | import { BoxHTMLProps } from "reakit/Box/Box";
| ^
4 | import { As, PropsWithAs } from "reakit-utils/types";
5 | import { splitProps } from "reakit-utils/splitProps";
6 | import { memo } from "./__utils/memo";
@AndresRodH Could you please create a new issue? Don't forget to include your TypeScript version and trying 1.0.0-beta.4
just to make sure it's not a problem with the new release. Thanks! :)
@diegohaz sure thing! I'll downgrade and try again.
@diegohaz I just wanted to say that I use Reakit in production, and while a lot of stuff got broken in .15
to .16
and now again (and I haven't upgraded yet) - on paper a lot of what you've written out here makes sense and I'm excited to upgrade. Especially ditching Flex
, FlexInline
, etc, I see as a great choice. Keep up the great work!
Questions
- Is the
Link
element removed? Is the equivalent<Box as="a">{children}</Box>
? - Are
fade
andslide
no longer a valid properties on<Popover />
? I feel these were really helpful.
Comments
Popover
Popover works extremely differently. For example, identical placement
yields entirely different results. I'm not sure how to replicate the .16
behavior. (I'll make a separate ticket for this)
Is the
Link
element removed? Is the equivalent<Box as="a">{children}</Box>
?
Yep! You can use Box
for this.
Are
fade
andslide
no longer a valid properties on<Popover />
? I feel these were really helpful.
They were removed because they relied on styles and the core library doesn't have styles anymore (only the necessary for accessibility).
There's an experimental unstable_animated
option that you can pass to useHiddenState
(and all its derivative modules, such as usePopoverState
) in order to produce the same behavior. This is still not as simple as passing a fade
/slide
prop, but in the future we may have a separate package to handle those animations more easily within Reakit (see how reakit-system-palette
handles colors, for instance).
Here's an example using unstable_animated
with code comments: https://codesandbox.io/s/reakit-animated-mm5u8
Popover works extremely differently.
It should work similarly. Will wait for the specific ticket.
Thank you so much for your contribution :)
Thanks for the reply! I agree it makes sense to move those features off to a secondary package like reakit-system-palette
, I just hope some portion of the Reakit ecosystem supports them.
Because popovers enter and leave the screen, I feel those options are helpful to providing a system that "just works," even if the implementations are suboptimal or hosted outside of reakit
core, or whatever else. I think the Dialog
element could benefit from the same, though I don't personally use it.
If you had to guess, what's the future of reakit-system-palette
look like? I'm okay with unstable as long as it's likely to continue to be developed and not disappear. And where exactly does it fit in with emotion-theming
?
Thanks again!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.