Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connect() returns an object #1300

Closed
rhalaly opened this issue Jun 2, 2019 · 9 comments
Closed

connect() returns an object #1300

rhalaly opened this issue Jun 2, 2019 · 9 comments

Comments

@rhalaly
Copy link

rhalaly commented Jun 2, 2019

I'm using these libraries:

react: 16.8.6
redux: 4.0.1
react-redux: 7.0.3

I have a simple component (Typescript):

class ExampleComponent extends React.PureComponent<IProps, {}> {
    constructor(props: any) {
        super(props);
    }

    public render() {
        return (
            <div>
                {this.props.name}
            </div>
        );
    }
}

interface IProps{
    name: string;
}

const mapStateToProps = (state) => {
    return {
        name: state.name
    };
}

export default connect(mapStateToProps)(ExampleComponent);

And I have a parent component:

import ExampleComponent from './ExampleComponent';

export default class App extends React.PureComponent<{}, {}> {
    constructor(props: any) {
        super(props);
    }

    public render() {
        return (
            <div>
                <ExampleComponent />
            </div>
        );
    }
}

For some reason the connect(mapStateToProps)(ExampleComponent) returns an object instead of React component.
I am getting an error:

Uncaught Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function but got: object

Also when I trying to do console.info(typeof connect(mapStateToProps)(ExampleComponent)) it prints object to the console.

How can I solve this issue?

@markerikson
Copy link
Contributor

Yes, as of React-Redux v7, connect() uses React.memo(), which actually returns a special object as a component type rather than a function.

Also, please make sure that you don't have duplicate copies of React in your tree, and that React truly is on React 16.8.x.

@rhalaly
Copy link
Author

rhalaly commented Jun 2, 2019

Thanks for the rapid assistance!

In the npm list command I can see that +-- react@16.8.6

Isn't it enought?

@markerikson
Copy link
Contributor

Should be, yes.

If you can create a sample project that reproduces the issue (preferably as a CodeSandbox), I can maybe take a quick look.

@rhalaly
Copy link
Author

rhalaly commented Jun 4, 2019

Thanks to CodeSandbox I found that the problem is with react-dom library. It was set to 16.4.xx by mistake so it didn't know how to handle those objects. Upgrading to 16.8.xx solved the problem.
Thanks!

@finom
Copy link

finom commented Jun 4, 2019

@markerikson is there any way to turn it off? I use the old react-router and it warns "Invalid prop component supplied to Route.".

@markerikson
Copy link
Contributor

@finom : no. connect() in React-Redux v7 uses React.memo(), and that's not changing. In addition, any code that assumes components are only functions has been wrong since React 16.6 came out.

If you're using an older version of React-Router, you need to either upgrade the router version, or stick with an older version of React-Redux.

@croraf
Copy link

croraf commented Jul 4, 2019

Yes. I found this today. And it is a pretty big issue unfortunately. withStyles() from material-ui also uses this memo, breaking some of my code. Upgrading react-router is the way to go.

But I use react-router-dom 4.3.1 and it does render but I get an error in the console:
index.js:1437 Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.

EDIT: I updated to react-router-dom 5.0.1 and now it works without errors in the console. Fixed somewhere between 4.3.1 and 5.0.1 of react-router-dom.

@finom
Copy link

finom commented Jul 4, 2019

Hello guys, I've found a solution to make it work with the old react-router and I suppose this should also work other outdated libraries. The solution is just to wrap the returned memorized component with a stateless component which isn't enhanced by memo:

const NonMemorizedNotFoundErrorPage = props => <NotFoundErrorPage {...props} />;
...
<Route path="/*" component={NonMemorizedNotFoundErrorPage} />

@SuhairZain
Copy link

Yes. I found this today. And it is a pretty big issue unfortunately. withStyles() from material-ui also uses this memo, breaking some of my code. Upgrading react-router is the way to go.

But I use react-router-dom 4.3.1 and it does render but I get an error in the console:
index.js:1437 Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.

EDIT: I updated to react-router-dom 5.0.1 and now it works without errors in the console. Fixed somewhere between 4.3.1 and 5.0.1 of react-router-dom.

It seems to be fixed in 5.0.0 as per the release notes and this version did fix the issue for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants