UNPKG

1.98 kBJavaScriptView Raw
1import { createElement, Component } from 'react';
2import shallowEqual from 'shallowequal'
3import hoistStatics from 'hoist-non-react-statics';
4import { storeShape } from './PropTypes';
5
6function getDisplayName(WrappedComponent) {
7 return WrappedComponent.displayName || WrappedComponent.name || 'Component';
8}
9
10const defaultMapStateToProps = () => ({});
11
12export default function connect(mapStateToProps) {
13 const shouldSubscribe = !!mapStateToProps;
14 const finnalMapStateToProps = mapStateToProps || defaultMapStateToProps;
15
16 return function wrapWithConnect(WrappedComponent) {
17 class Connect extends Component {
18 static displayName = `Connect(${getDisplayName(WrappedComponent)})`;
19
20 static contextTypes = {
21 store: storeShape.isRequired,
22 };
23
24 constructor(props, context) {
25 super(props, context);
26
27 this.store = context.store;
28 this.state = { subscribed: finnalMapStateToProps(this.store.getState(), props) };
29 }
30
31 componentDidMount() {
32 this.trySubscribe();
33 }
34
35 componentWillUnmount() {
36 this.tryUnsubscribe();
37 }
38
39 handleChange = () => {
40 if (!this.unsubscribe) {
41 return;
42 }
43
44 const nextState = finnalMapStateToProps(this.store.getState(), this.props);
45 if (!shallowEqual(this.state.subscribed, nextState)) {
46 this.setState({ subscribed: nextState });
47 }
48 };
49
50 trySubscribe() {
51 if (shouldSubscribe) {
52 this.unsubscribe = this.store.subscribe(this.handleChange);
53 this.handleChange();
54 }
55 }
56
57 tryUnsubscribe() {
58 if (this.unsubscribe) {
59 this.unsubscribe();
60 this.unsubscribe = null;
61 }
62 }
63
64 render() {
65 return createElement(WrappedComponent, {
66 ...this.props,
67 ...this.state.subscribed,
68 store: this.store,
69 });
70 }
71 }
72
73 return hoistStatics(Connect, WrappedComponent);
74 };
75}