diff --git a/dist/index.d.ts b/dist/index.d.ts index ffd5351..b7f847c 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,29 +1,27 @@ -declare module 'react-waterfall' { +import { ComponentType } from 'react'; - import React from 'react' +export type Action = (...args: any[]) => void +export type Actions = { + [K: string]: Action +} +export type Store = { + initialState: T + actions: { + [K in keyof A]: (state: T, ...args: any[]) => T | Promise + } +} - declare type State = any - declare type Self = any - declare type Action = (state: State) => any - declare type Actions = { [key: string]: Action } - declare type Subscriber = (action: Action, state: State) => void +export type Subscriber = (action: keyof A, state: T, ...args: any[]) => void - declare type Store = { - initialState: State - actions: Actions - } +export type Middleware = (store: Store, self: ComponentType) => (action: keyof A, ...args: any[]) => void - declare type Middleware = (store: Store, self: Self) => (action: string) => void +export type Connect = (selector: (state: T) => P) => (baseComponet: ComponentType) => ComponentType - declare export const initStore: ( - state: any, - middlewares?: Middleware[], - ) => { - Provider: React.Component - Consumer: React.Component - connect: (state: any) => (component: React.Component) => React.Component - actions: Actions - getState: () => State - subscribe: Subscriber - } +export function initStore>(store: Store, ...middlewares: Middleware[]): { + Provider: ComponentType + Consumer: ComponentType + connect: Connect + actions: A + getState: () => T + subscribe: (subscruber: Subscriber) => void } diff --git a/src/__tests__/index.spec.js b/src/__tests__/index.spec.js index d2d5cf2..9186db0 100644 --- a/src/__tests__/index.spec.js +++ b/src/__tests__/index.spec.js @@ -26,6 +26,7 @@ describe('initStore', () => { expect(storeContext.getState).toBeDefined() expect(storeContext.connect).toBeDefined() expect(storeContext.subscribe).toBeDefined() + expect(storeContext.unsubscribe).toBeDefined() }) test('should fail an action if provider not initialized', () => { @@ -92,6 +93,22 @@ describe('initStore', () => { expect(subscriber).toHaveBeenCalledTimes(1) }) + test('should remove subscribers on unsubscribe', () => { + const { connect, Provider, actions, subscribe, unsubscribe } = initStore(mockStore) + const Count = connect(state => ({ count: state.count }))(TestCount) + const subscriber = jest.fn() + subscribe(subscriber) + const component = renderer.create( + + + + ); + unsubscribe(subscriber) + actions.increment() + component.toJSON() // invoke render + expect(subscriber).toHaveBeenCalledTimes(0) + }) + test('should allow action to return a promise', () => { const { connect, Provider, actions, subscribe } = initStore(mockStore) const Count = connect(state => ({ count: state.count }))(TestCount) diff --git a/src/index.js b/src/index.js index f2fb234..5f4ca3e 100644 --- a/src/index.js +++ b/src/index.js @@ -25,6 +25,10 @@ export const initStore: Function = (store, ...middlewares) => { subscriptions = [...subscriptions, fn] } + const unsubscribe = fn => { + subscriptions = subscriptions.filter(subscriber => subscriber !== fn) + } + const actions = Object.keys(store.actions).reduce( (r, v) => ({ ...r, @@ -48,9 +52,9 @@ export const initStore: Function = (store, ...middlewares) => { _children = () => this.props.children prevent = ({ state, actions }) => { - const { mapStateToProps } = this.props + const { mapStateToProps, children /* exclude children from rest */, ...rest } = this.props return ( - + ) } @@ -64,9 +68,9 @@ export const initStore: Function = (store, ...middlewares) => { } const connect = mapStateToProps => WrappedComponent => { - const ConnectComponent = (props) => - - {injectedProps => } + const ConnectComponent = props => + + {injectedProps => } ConnectComponent.displayName = `Connect(${WrappedComponent.displayName || WrappedComponent.name || 'Unknown'})` return ConnectComponent @@ -104,5 +108,6 @@ export const initStore: Function = (store, ...middlewares) => { getState, connect, subscribe, + unsubscribe, } }