Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HOC import TypeError: Object(...) is not a function

I just tried to use a simple HOC with react. Here is the function :

import React from "react"

const withOptions = (WrappedComponent) => {

  return class extends React.Component {

    render() {
      return <WrappedComponent { ...this.props } />
    }
  }

}

export default withOptions

The problem seems to be in the way i export/import it.

Imported and used in a simple way, it works :

import withOptions from "./Options"
...

class BilanClimatique extends React.Component{
  ...
}
const StyledBilanClimatique = withStyles(styles)(BilanClimatique)
export default withOptions(StyledBilanClimatique)

But if i use an intermediate file like index.js

import withOptions from "./Options"

export {
  withOptions
}

And import it in my component like that

import {
  withOptions
} from "./index"

Here is what i get

HOC error

Can someone help me understand this ?

EDIT :

I found that the component that is using the HOC is imported from the same file as the HOC :

import withOptions from "./Options"
import BilanClimatique from "./BilanClimatique"

export {
  withOptions,
  BilanClimatique
}

And that causes the problem, but I don't understand why... Here is a sandbox with the problem https://codesandbox.io/s/r074735yvo

like image 255
Jayffe Avatar asked Dec 24 '22 05:12

Jayffe


1 Answers

This seems to be a problem with hoisting of 'exports'. From what I can see, the imports get hoisted, but I could not see anything similar for exports.

The flow which causes problem (codesandbox):

App.js:

import { BilanClimatique } from "./components/index";

./components/index.js:

// just using the "re-export" shortcut
export { default as BilanClimatique } from "./BilanClimatique";
export { default as withOptions } from "./Options";

./components/BilanClimatique.js:

import { withOptions } from "./index";

./components/Options.js:

const withOptions = WrappedComponent => {
  return ... //snipped code

export default withOptions;

When App.js asks index.js for BilanClimatique, it in turn asks the same index.js for withOptions. But since exports don't seem to be hoisted, index.js has not yet made withOptions available.

How to solve:

  1. Ordered exports:

in ./components/index.js, change the order of exports as per your dependency:

// just using the "re-export" shortcut
export { default as withOptions } from "./Options";
export { default as BilanClimatique } from "./BilanClimatique";

I would not recommend it. It is very fragile.

  1. Use index.js to only expose to outside your namespace. Inside your namespace, rely on explicit imports.

i.e. in ./components/BilanClimatique.js:

import withOptions from "./Options";
  1. If you have a very large codebase, use multiple index.js for exporting your "contracts". Take a look at the codebases of various library authors, I think that is the strategy they take.

I would personally recommend #2 over #3 unless you run into problems with #2.

like image 90
dubes Avatar answered Dec 25 '22 23:12

dubes