I'm creating this issue to propose an enhancement over how we pass state to components. Instead of having to pass it for all components, we would only need to pass it to the top-level ones.
For example, currently we have to pass the state to all instances of MenuItem inside Menu:
const state = useMenuState();
<MenuButton {...state}>Open menu</MenuButton>
<Menu {...state}>
<MenuArrow {...state} />
<MenuItem {...state}>Item 1</MenuItem>
<MenuItem {...state}>Item 2</MenuItem>
<MenuSeparator {...state} />
<MenuItem {...state}>Item 3</MenuItem>
</Menu>
I'm proposing that we improve this so we don't need to explicitly pass state to MenuItem instances anymore. It would leverage React Context and subscribe to state changes internally.
const state = useMenuState();
<MenuButton {...state}>Open menu</MenuButton>
<Menu {...state}>
<MenuArrow />
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuSeparator />
<MenuItem>Item 3</MenuItem>
</Menu>
Note: MenuItem should keep accepting state being passed directly as props for this reason. But it wouldn't be required anymore.
Motivation
Besides being easier to write code like that, it would also make it easier to colocate state.
In our Menu example, all MenuItem components will re-render when state gets updated. But if we abstract the state into a separate component that receives children, they won't re-render:
import {
useMenuState,
Menu as BaseMenu,
MenuButton,
MenuItem,
} from \"reakit/Menu\";
function Menu({ button, ...props }) {
const state = useMenuState();
return (
<React.Fragment>
<MenuButton {...state} ref={button.ref} {...button.props}>
{(buttonProps) => React.cloneElement(button, buttonProps)}
</MenuButton>
<BaseMenu {...state} {...props} />
</React.Fragment>
);
}
function App() {
return (
<Menu button={<button>Open menu</button>}>
<MenuItem>Item 1</MenuItem>
<MenuItem>Item 2</MenuItem>
<MenuItem>Item 3</MenuItem>
...
<MenuItem>Item 500</MenuItem>
</Menu>
);
}
I'm creating this issue to propose an enhancement over how we pass state to components. Instead of having to pass it for all components, we would only need to pass it to the top-level ones.
For example, currently we have to pass the state to all instances of
MenuIteminsideMenu:I'm proposing that we improve this so we don't need to explicitly pass state to
MenuIteminstances anymore. It would leverage React Context and subscribe to state changes internally.Note:
MenuItemshould keep accepting state being passed directly as props for this reason. But it wouldn't be required anymore.Motivation
Besides being easier to write code like that, it would also make it easier to colocate state.
In our
Menuexample, allMenuItemcomponents will re-render whenstategets updated. But if we abstract the state into a separate component that receiveschildren, they won't re-render: