I have a functional component that required props height
and width
to be rendered. Let's call it PureSizableDiv
:
const PureSizableDiv = ({ height, width }) =>
<div style={{ height, width }}>I'm a div!</div>
I also have a React context called Size
:
import React from 'react';
import { compose, fromRenderProps } from 'recompose';
export const { SizeProvider, SizeConsumer } = React.createContext({
height: null,
width: null,
});
Instead of manually creating a new HoC like this:
export const withSize = Component => (props) =>
<SizeConsumer>
{
({ height, width }) =>
<Component
height={height}
width={width}
{...props}
/>
}
</SizeConsumer>;
I'd like to know if there's a shorter a cleaner way using recompose
to do this.
I tried
export const withSize = compose(
fromRenderProps(SizeConsumer, ({ height, width }) => ({ height, width })),
);
But got the error Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
I had connected my component, but I wasn't using properly the Context API.
I fixed the code and it worked flawlessly using fromRenderProps
from recompose
.
Working code:
import React from 'react';
import { compose, fromRenderProps } from 'recompose';
const PureSizableDiv = ({ height, width }) =>
<div style={{ height, width }}>I am a div!</div>;
const SizeContext = React.createContext({
height: null,
width: null,
});
const withSize = compose(
fromRenderProps(SizeContext.Consumer, ({ height, width }) => ({ height, width })),
);
// Usage
const Wrapper = ({ children, height, width }) =>
<SizeContext.Provider
value={{
height: height,
width: width,
}}
>
{children}
</SizeContext.Provider>;
const SizedDiv = withSize(PureSizableDiv);
// Render components
<Wrapper>
<SizedDiv/>
</Wrapper>