import React, { Component, ReactNode } from 'react' const isServer = typeof window === 'undefined' type State = Array> | undefined type SideEffectProps = { reduceComponentsToState: ( components: Array>, props: T ) => State handleStateChange?: (state: State) => void isAmp?: boolean } export default () => { const mountedInstances: Set = new Set() let state: State function emitChange(component: React.Component) { state = component.props.reduceComponentsToState( [...mountedInstances], component.props ) if (component.props.handleStateChange) { component.props.handleStateChange(state) } } return class extends Component { // Used when server rendering static rewind() { const recordedState = state state = undefined mountedInstances.clear() return recordedState } constructor(props: any) { super(props) if (isServer) { mountedInstances.add(this) emitChange(this) } } componentDidMount() { mountedInstances.add(this) emitChange(this) } componentDidUpdate() { emitChange(this) } componentWillUnmount() { mountedInstances.delete(this) emitChange(this) } render() { return null } } }