diff --git a/package.json b/package.json index 622f630..e71fcd7 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "redux-devtools": "^3.0.0" }, "dependencies": { + "lodash.debounce": "^4.0.4", "react-json-tree": "^0.6.5", "react-pure-render": "^1.0.2", "redux-devtools-themes": "^1.0.0" diff --git a/src/LogMonitor.js b/src/LogMonitor.js index c760b92..0049315 100644 --- a/src/LogMonitor.js +++ b/src/LogMonitor.js @@ -1,11 +1,12 @@ import React, { PropTypes, Component } from 'react'; -import LogMonitorEntry from './LogMonitorEntry'; import LogMonitorButton from './LogMonitorButton'; import shouldPureComponentUpdate from 'react-pure-render/function'; import * as themes from 'redux-devtools-themes'; import { ActionCreators } from 'redux-devtools'; import { updateScrollTop } from './actions'; import reducer from './reducers'; +import LogMonitorEntryList from './LogMonitorEntryList'; +import debounce from 'lodash.debounce'; const { reset, rollback, commit, sweep, toggleAction } = ActionCreators; @@ -72,6 +73,11 @@ export default class LogMonitor extends Component { shouldComponentUpdate = shouldPureComponentUpdate; + updateScrollTop = debounce(() => { + const node = this.refs.container; + this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0)); + }, 500); + constructor(props) { super(props); this.handleToggleAction = this.handleToggleAction.bind(this); @@ -101,7 +107,7 @@ export default class LogMonitor extends Component { if (this.props.preserveScrollTop) { node.scrollTop = this.props.monitorState.initialScrollTop; - this.interval = setInterval(::this.updateScrollTop, 1000); + node.addEventListener('scroll', this.updateScrollTop); } else { this.scrollDown = true; this.scroll(); @@ -109,14 +115,10 @@ export default class LogMonitor extends Component { } componentWillUnmount() { - if (this.interval) { - clearInterval(this.interval); - } - } - - updateScrollTop() { const node = this.refs.container; - this.props.dispatch(updateScrollTop(node ? node.scrollTop : 0)); + if (node && this.props.preserveScrollTop) { + node.removeEventListener('scroll', this.updateScrollTop); + } } componentWillReceiveProps(nextProps) { @@ -176,33 +178,28 @@ export default class LogMonitor extends Component { } render() { - const elements = []; const theme = this.getTheme(); - const { actionsById, skippedActionIds, stagedActionIds, computedStates, select } = this.props; - - for (let i = 0; i < stagedActionIds.length; i++) { - const actionId = stagedActionIds[i]; - const action = actionsById[actionId].action; - const { state, error } = computedStates[i]; - let previousState; - if (i > 0) { - previousState = computedStates[i - 1].state; - } - elements.push( - -1} - error={error} - expandActionRoot={this.props.expandActionRoot} - expandStateRoot={this.props.expandStateRoot} - onActionClick={this.handleToggleAction} /> - ); - } + const { + actionsById, + skippedActionIds, + stagedActionIds, + computedStates, + select, + expandActionRoot, + expandStateRoot + } = this.props; + + const entryListProps = { + theme, + actionsById, + skippedActionIds, + stagedActionIds, + computedStates, + select, + expandActionRoot, + expandStateRoot, + onActionClick: this.handleToggleAction + }; return (
@@ -233,7 +230,7 @@ export default class LogMonitor extends Component {
- {elements} +
); diff --git a/src/LogMonitorEntryList.js b/src/LogMonitorEntryList.js new file mode 100644 index 0000000..5b73ba2 --- /dev/null +++ b/src/LogMonitorEntryList.js @@ -0,0 +1,67 @@ +import React, { PropTypes, Component } from 'react'; +import LogMonitorEntry from './LogMonitorEntry'; +import shouldPureComponentUpdate from 'react-pure-render/function'; + +export default class LogMonitorEntryList extends Component { + + static propTypes = { + actionsById: PropTypes.object, + computedStates: PropTypes.array, + stagedActionIds: PropTypes.array, + skippedActionIds: PropTypes.array, + + select: PropTypes.func.isRequired, + onActionClick: PropTypes.func.isRequired, + theme: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.string + ]), + expandActionRoot: PropTypes.bool, + expandStateRoot: PropTypes.bool + }; + + shouldComponentUpdate = shouldPureComponentUpdate; + + render() { + const elements = []; + const { + theme, + actionsById, + computedStates, + select, + skippedActionIds, + stagedActionIds, + expandActionRoot, + expandStateRoot, + onActionClick + } = this.props; + + for (let i = 0; i < stagedActionIds.length; i++) { + const actionId = stagedActionIds[i]; + const action = actionsById[actionId].action; + const { state, error } = computedStates[i]; + let previousState; + if (i > 0) { + previousState = computedStates[i - 1].state; + } + elements.push( + -1} + error={error} + expandActionRoot={expandActionRoot} + expandStateRoot={expandStateRoot} + onActionClick={onActionClick} /> + ); + } + + return (
+ {elements} +
); + } +}