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 } } }