forked from elastic/search-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwithSearch.js
87 lines (76 loc) · 2.8 KB
/
withSearch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import React from "react";
import SearchContext from "./SearchContext";
function buildContextForProps(context) {
return {
...context.driver.getState(),
...context.driver.getActions()
};
}
/* For a given object execute mapContextToProps to pluck out the relevant
properties */
function giveMeJustWhatINeeded(stateOrContext, mapContextToProps, props) {
const mapContextToPropsToUse = props.mapContextToProps || mapContextToProps;
return mapContextToPropsToUse(stateOrContext, props) || {};
}
/**
* This is a Higher Order Component that wraps a component and injects state and actions from Search UI, effectively
* "connecting" it to Search UI.
*
* Components using `withSearch` will be "Pure" components.
* It is important to understand the implications of using a PureComponent, as described here:
* https://reactjs.org/docs/optimizing-performance.html#examples
*
* @param Function mapContextToProps A function that accepts the context and allows you to pick the values to be passed as props
* into the component. This allows you to "select" which values from the context to use.
* @param Function Component
*/
export default function withSearch(mapContextToProps) {
if (!mapContextToProps) {
throw "withSearch requires a function to be provided which returns an object with at least one value.";
}
return function(Component) {
class WithSearch extends React.PureComponent {
constructor(props, context) {
super();
this.state = {
...giveMeJustWhatINeeded(
buildContextForProps(context),
// eslint-disable-next-line react/prop-types
mapContextToProps,
props
)
};
// Note that we subscribe to changes at the component level, rather than
// at the top level Provider, so that we are re-rendering the entire
// subtree when state changes in the Provider.
context.driver.subscribeToStateChanges(this.subscription);
}
componentWillUnmount() {
this.unmounted = true;
this.context.driver.unsubscribeToStateChanges(this.subscription);
}
subscription = state => {
if (this.unmounted) return;
this.setState(prevState =>
giveMeJustWhatINeeded(
{
// We pass prevState here instead of just state so that actions are
// persisted as well, which are not passed in the subscription param
...prevState,
...state
},
mapContextToProps,
this.props
)
);
};
render() {
// eslint-disable-next-line react/prop-types
const { ...rest } = this.props;
return <Component {...this.state} {...rest} />;
}
}
WithSearch.contextType = SearchContext;
return WithSearch;
};
}