-
-
Save gaearon/1d19088790e70ac32ea636c025ba424e to your computer and use it in GitHub Desktop.
// connect() is a function that injects Redux-related props into your component. | |
// You can inject data and callbacks that change that data by dispatching actions. | |
function connect(mapStateToProps, mapDispatchToProps) { | |
// It lets us inject component as the last step so people can use it as a decorator. | |
// Generally you don't need to worry about it. | |
return function (WrappedComponent) { | |
// It returns a component | |
return class extends React.Component { | |
render() { | |
return ( | |
// that renders your component | |
<WrappedComponent | |
{/* with its props */} | |
{...this.props} | |
{/* and additional props calculated from Redux store */} | |
{...mapStateToProps(store.getState(), this.props)} | |
{...mapDispatchToProps(store.dispatch, this.props)} | |
/> | |
) | |
} | |
componentDidMount() { | |
// it remembers to subscribe to the store so it doesn't miss updates | |
this.unsubscribe = store.subscribe(this.handleChange.bind(this)) | |
} | |
componentWillUnmount() { | |
// and unsubscribe later | |
this.unsubscribe() | |
} | |
handleChange() { | |
// and whenever the store state changes, it re-renders. | |
this.forceUpdate() | |
} | |
} | |
} | |
} | |
// This is not the real implementation but a mental model. | |
// It skips the question of where we get the "store" from (answer: <Provider> puts it in React context) | |
// and it skips any performance optimizations (real connect() makes sure we don't re-render in vain). | |
// The purpose of connect() is that you don't have to think about | |
// subscribing to the store or perf optimizations yourself, and | |
// instead you can specify how to get props based on Redux store state: | |
const ConnectedCounter = connect( | |
// Given Redux state, return props | |
state => ({ | |
value: state.counter, | |
}), | |
// Given Redux dispatch, return callback props | |
dispatch => ({ | |
onIncrement() { | |
dispatch({ type: 'INCREMENT' }) | |
} | |
}) | |
)(Counter) |
Aha moment ! Concise and powerful : terms we hardly associate together with libraries.
👍
here is my decorator to simplify things:
import React from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import * as actions from "./actions";
const decorator = ComponentToDecorate => {
class ComponentDecorated extends React.Component {
render() {
const { authState, authActions, ...rest } = this.props;
return (
<ComponentToDecorate auth={{ state: authState, actions: authActions }}
{...rest}
/>
);
}
}
return connect(
state => ({
authState: state.services.auth.authentication
}),
dispatch => ({
authActions: bindActionCreators(actions, dispatch)
})
)(ComponentDecorated);
};
export default decorator;
i use it in some complicated components. is there is anything wrong with this?
fantastic! clear and concise, thanks @gaearon
Thank you,very clear explanation,like you methods to educate.
Especially , you approach when you explain how things work under the hood!
Good and brief explanation
Fantastic work!
Can this be used in prod?
Hooks?
So connect actually returns a new component hah !!! thanks for this snippet
If I use this syntax.
const mapState = ({ state }) => ({ ...state });
- The component will be heavy?
- The component will be re-render every time store change?
- The component will take extra memory to store props?
- Or it's just a syntactic sugar?
Great Explanation!
This helped. Thank you!
Is it accurate to say that connect
implements some variant of the observer pattern? If yes or no (or kinda), why?
@ezmiller i would say - connect()
is an observer for sure. Why? Go to the internet
I just came here to see how a HOC works in practical. Thanks for this explaination.
@gaearon don't you think the subscription logic should be in the constructor
and not componentDidMount
? If I am dispatching an action from WrappedComponent
's componentDidMount
. We won't see the updated state (it wont re render) in WrappedComponent
, since componentDidMount
of the WrappedComponent
will run first before the subscription happens in componentDidMount
inside connect()
Very clear explanation! 👍
Thank You That was a clear explanation !!
Thanks, this mental model helping me a lot while learning react with redux :)
thanks @gaearon
Thank you 🚀🚀🚀
Thank you so much. It was so helpful.
thanks!
Wow this is great 👍