This repository was archived by the owner on Jun 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathNotifyObservers.react.js
121 lines (107 loc) · 3.51 KB
/
NotifyObservers.react.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import {connect} from 'react-redux';
import {isEmpty} from 'ramda';
import {notifyObservers, updateProps} from '../../actions';
import React from 'react';
import PropTypes from 'prop-types';
/*
* NotifyObservers passes a connected `setProps` handler down to
* its child as a prop
*/
function mapStateToProps(state) {
return {
dependencies: state.dependenciesRequest.content,
paths: state.paths,
};
}
function mapDispatchToProps(dispatch) {
return {dispatch};
}
function mergeProps(stateProps, dispatchProps, ownProps) {
const {dispatch} = dispatchProps;
return {
id: ownProps.id,
children: ownProps.children,
dependencies: stateProps.dependencies,
paths: stateProps.paths,
fireEvent: function fireEvent({event}) {
// Update this component's observers with the updated props
dispatch(notifyObservers({event, id: ownProps.id}));
},
setProps: function setProps(newProps) {
const payload = {
props: newProps,
id: ownProps.id,
itempath: stateProps.paths[ownProps.id],
};
// Update this component's props
dispatch(updateProps(payload));
// Update output components that depend on this input
dispatch(notifyObservers({id: ownProps.id, props: newProps}));
},
};
}
function NotifyObserversComponent({
children,
id,
paths,
dependencies,
fireEvent,
setProps,
}) {
const thisComponentTriggersEvents =
dependencies &&
dependencies.find(dependency =>
dependency.events.find(event => event.id === id)
);
const thisComponentSharesState =
dependencies &&
dependencies.find(
dependency =>
dependency.inputs.find(input => input.id === id) ||
dependency.state.find(state => state.id === id)
);
/*
* Only pass in `setProps` and `fireEvent` if they are actually
* necessary.
* This allows component authors to skip computing data
* for `setProps` or `fireEvent` (which can be expensive)
* in the case when they aren't actually used.
* For example, consider `hoverData` for graphs. If it isn't
* actually used, then the component author can skip binding
* the events for the component.
*
* TODO - A nice enhancement would be to pass in the actual events
* and properties that are used into the component so that the
* component author can check for something like `subscribed_events`
* or `subscribed_properties` instead of `fireEvent` and `setProps`.
*/
const extraProps = {};
if (
thisComponentSharesState &&
// there is a bug with graphs right now where
// the restyle listener gets assigned with a
// setProps function that was created before
// the item was added. only pass in setProps
// if the item's path exists for now.
paths[id]
) {
extraProps.setProps = setProps;
}
if (thisComponentTriggersEvents && paths[id]) {
extraProps.fireEvent = fireEvent;
}
if (!isEmpty(extraProps)) {
return React.cloneElement(children, extraProps);
}
return children;
}
NotifyObserversComponent.propTypes = {
id: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
path: PropTypes.array.isRequired,
};
export default connect(
mapStateToProps,
mapDispatchToProps,
mergeProps
)(NotifyObserversComponent);