Augusto Franzoia
Augusto Franzoia

Reputation: 625

Use recompose to map props consumed from context

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.

Upvotes: 2

Views: 1435

Answers (2)

Augusto Franzoia
Augusto Franzoia

Reputation: 625

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>

Upvotes: 4

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

The error is appearing it's because you're not exporting the Component with the compose:

export const withSize = compose(
  fromRenderProps(SizeConsumer, ({ height, width }) => ({ height, width })),
)(Component);
// ^^

Upvotes: 2

Related Questions