Does anyone know how to wrap a React component with React.memo
when one is using the connect
function from react-redux?
For example, how would you modify the following?
let Button = (props: Props) => (
<button onClick={props.click}>{props.value}</button>
);
Button = connect(
mapStateToProps,
mapDispatchToProps
)(Button);
I've tried:
let Button = React.memo((props: Props) => (
<button onClick={props.click}>{props.value}</button>
));
Button = connect(
mapStateToProps,
mapDispatchToProps
)(Button);
However, the function returned by connect
expects a component to be passed so it errors with:
Uncaught Error: You must pass a component to the function returned by connect. Instead received {"compare":null}
React.memo
is nothing but a HOC, so you can just use:
Without memo:
connect(
mapStateToProps,
mapDispatchToProps
)(Button);
With memo:
connect(
mapStateToProps,
mapDispatchToProps
)(React.memo(Button));
And even wrap to connect: (This should be the solution with connect)
React.memo(
connect(
mapStateToProps,
mapDispatchToProps
)(Button)
);
Like we do with withRouter
: withRouter(connect(...)())
Same issue here. Fixed by upgrading react-redux
to version 5.1.0.
Your solution should work (I didn't try copy-pasted like that), but you also have to update react-redux
to the latest version.
By the way, I think the proper implementation of React.memo
within many HOC would be to be the closest to the component itself : the goal of React.memo
is to check if all the new props received by the component are the same as the last props. If any HOC transforms or adds any props to the component - which connect
does by mapping the Redux store to the props, React.memo
should be aware of it in order to decide wether or not to update the component.
So I would go for something like that :
//import what you need to import
const Component = props => <div>{/* do what you need to do here */}</div>
export default compose(
connect(mapStateToProps, dispatchToProps),
/* any other HOC*/
React.memo
)(Component);
As the error message says, you need to pass a component to the returned function from connect
.
( which means the second pair of () in connect()()
)
As React.Memo
returns a component, pass it into the second function of connect
.
Here's how you can do this.
export const MemoizedDemoComponent = connect(mapStateToProps)(React.memo(DemoComponent);
Demo component:
import React from "react";
import { connect } from "react-redux";
const DemoComponent = props => (
<div>
<p>My demo component fueled by: {props.fuel}!</p>
<p>Redux: {props.state}</p>
</div>
);
const mapStateToProps = state => ({
state: "your redux state..."
});
// create a version that only renders on prop changes
export const MemoizedDemoComponent = connect(mapStateToProps)(
React.memo(DemoComponent)
);
For a working example check also codesandbox .
For someone who want to know why react-redux
throw this error.
For me, I used version 5.0.7
, react-redux/src/components/connectAdvanced.js
line: 92
invariant(
typeof WrappedComponent == 'function',
`You must pass a component to the function returned by ` +
`${methodName}. Instead received ${JSON.stringify(WrappedComponent)}`
);
After upgrading this code is changed to:
invariant(
isValidElementType(WrappedComponent),
`You must pass a component to the function returned by ` +
`${methodName}. Instead received ${JSON.stringify(WrappedComponent)}`
);
How to check the WrappedComponent
is changed to isValidElementType(WrappedComponent)
which is exposed by react-is
So, yarn update react-redux
to the version that mentioned by @Maxime Chéramy at least
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.