// Copyright 2017-2026 @pezkuwi/react-api authors & contributors // SPDX-License-Identifier: Apache-2.0 // TODO: Lots of duplicated code between this and withObservable, surely there is a better way of doing this? import type { Observable, OperatorFunction } from 'rxjs'; import type { CallState } from '../types.js'; import type { DefaultProps, HOC, Options, RenderFn } from './types.js'; import React from 'react'; import { catchError, map, of } from 'rxjs'; import echoTransform from '../transform/echo.js'; import { intervalObservable, isEqual, triggerChange } from '../util/index.js'; interface State extends CallState { subscriptions: { unsubscribe: () => void }[]; } export default function withObservable (observable: Observable

, { callOnResult, propName = 'value', transform = echoTransform }: Options = {}): HOC { return (Inner: React.ComponentType, defaultProps: DefaultProps = {}, render?: RenderFn): React.ComponentType => { class WithObservable extends React.Component { private isActive = true; public override state: State = { callResult: undefined, callUpdated: false, callUpdatedAt: 0, subscriptions: [] }; public override componentDidMount (): void { this.setState({ subscriptions: [ observable .pipe( map(transform) as OperatorFunction, catchError(() => of(undefined)) ) .subscribe((value) => this.triggerUpdate(this.props, value as T)), intervalObservable(this) ] }); } public override componentWillUnmount (): void { this.isActive = false; this.state.subscriptions.forEach((subscription): void => subscription.unsubscribe() ); } private triggerUpdate = (props: P, callResult?: T): void => { try { if (!this.isActive || isEqual(callResult, this.state.callResult)) { return; } triggerChange(callResult, callOnResult, (props as Options).callOnResult || defaultProps.callOnResult); this.setState({ callResult, callUpdated: true, callUpdatedAt: Date.now() }); } catch (error) { console.error(this.props, error); } }; public override render (): React.ReactNode { const { children } = this.props; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const { callResult, callUpdated, callUpdatedAt } = this.state; const _props = { ...defaultProps, ...this.props, callUpdated, callUpdatedAt, [propName]: callResult }; return ( {render?.(callResult)}{children} ); } } return WithObservable; }; }