2019-03-27 17:46:44 +01:00
|
|
|
import React, { Component, ReactNode } from 'react'
|
2019-01-25 01:39:15 +01:00
|
|
|
|
|
|
|
const isServer = typeof window === 'undefined'
|
|
|
|
|
2019-01-25 16:43:12 +01:00
|
|
|
type State = Array<React.ReactElement<any>> | undefined
|
2019-01-25 01:39:15 +01:00
|
|
|
|
|
|
|
type SideEffectProps = {
|
2019-03-27 17:46:44 +01:00
|
|
|
reduceComponentsToState: <T>(components: Array<React.ReactElement<any>>, props: T) => State,
|
2019-01-25 16:43:12 +01:00
|
|
|
handleStateChange?: (state: State) => void,
|
2019-04-24 16:47:50 +02:00
|
|
|
isAmp?: boolean,
|
2019-01-25 01:39:15 +01:00
|
|
|
}
|
|
|
|
|
2019-04-24 16:47:50 +02:00
|
|
|
export default () => {
|
2019-01-25 01:39:15 +01:00
|
|
|
const mountedInstances: Set<any> = new Set()
|
|
|
|
let state: State
|
|
|
|
|
2019-04-24 16:47:50 +02:00
|
|
|
function emitChange(component: React.Component<SideEffectProps>) {
|
2019-03-27 17:46:44 +01:00
|
|
|
state = component.props.reduceComponentsToState([...mountedInstances], component.props)
|
2019-01-25 16:43:12 +01:00
|
|
|
if (component.props.handleStateChange) {
|
2019-01-25 01:39:15 +01:00
|
|
|
component.props.handleStateChange(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-24 16:47:50 +02:00
|
|
|
return class extends Component<SideEffectProps> {
|
2019-01-25 01:39:15 +01:00
|
|
|
// Used when server rendering
|
2019-01-25 16:43:12 +01:00
|
|
|
static rewind() {
|
2019-01-25 01:39:15 +01:00
|
|
|
const recordedState = state
|
|
|
|
state = undefined
|
|
|
|
mountedInstances.clear()
|
|
|
|
return recordedState
|
|
|
|
}
|
|
|
|
|
2019-01-25 16:43:12 +01:00
|
|
|
constructor(props: any) {
|
2019-01-25 01:39:15 +01:00
|
|
|
super(props)
|
|
|
|
if (isServer) {
|
|
|
|
mountedInstances.add(this)
|
|
|
|
emitChange(this)
|
|
|
|
}
|
|
|
|
}
|
2019-01-25 16:43:12 +01:00
|
|
|
componentDidMount() {
|
2019-01-25 01:39:15 +01:00
|
|
|
mountedInstances.add(this)
|
|
|
|
emitChange(this)
|
|
|
|
}
|
2019-01-25 16:43:12 +01:00
|
|
|
componentDidUpdate() {
|
2019-01-25 01:39:15 +01:00
|
|
|
emitChange(this)
|
|
|
|
}
|
2019-01-25 16:43:12 +01:00
|
|
|
componentWillUnmount() {
|
2019-01-25 01:39:15 +01:00
|
|
|
mountedInstances.delete(this)
|
|
|
|
emitChange(this)
|
|
|
|
}
|
|
|
|
|
2019-01-25 16:43:12 +01:00
|
|
|
render() {
|
2019-01-25 01:39:15 +01:00
|
|
|
return null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|