import React, { Context, ReactNode, useMemo } from 'react' import { ReactReduxContext, ReactReduxContextValue } from './Context' import { createSubscription } from '../utils/Subscription' import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect' import { Action, AnyAction, Store } from 'redux' export interface ProviderProps { /** * The single Redux store in your application. */ store: Store /** * An optional server state snapshot. Will be used during initial hydration render if available, to ensure that the UI output is consistent with the HTML generated on the server. */ serverState?: S /** * Optional context to be used internally in react-redux. Use React.createContext() to create a context to be used. * If this is used, you'll need to customize `connect` by supplying the same context provided to the Provider. * Initial value doesn't matter, as it is overwritten with the internal state of Provider. */ context?: Context> children: ReactNode } function Provider({ store, context, children, serverState, }: ProviderProps) { const contextValue = useMemo(() => { const subscription = createSubscription(store) return { store, subscription, getServerState: serverState ? () => serverState : undefined, } }, [store, serverState]) const previousState = useMemo(() => store.getState(), [store]) useIsomorphicLayoutEffect(() => { const { subscription } = contextValue subscription.onStateChange = subscription.notifyNestedSubs subscription.trySubscribe() if (previousState !== store.getState()) { subscription.notifyNestedSubs() } return () => { subscription.tryUnsubscribe() subscription.onStateChange = undefined } }, [contextValue, previousState]) const Context = context || ReactReduxContext // @ts-ignore 'AnyAction' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype return {children} } export default Provider