diff --git a/packages/client/src/redux/Connector.ts b/packages/client/src/redux/Connector.ts index bccff8e..fe05f0c 100644 --- a/packages/client/src/redux/Connector.ts +++ b/packages/client/src/redux/Connector.ts @@ -17,8 +17,6 @@ import {ComponentType} from 'react' * the Actions class might depend on the HTTPClient class, and then it becomes * easy to mock it during tests, or swap out different dependencies for * different applications. - * - * @deprecated */ export abstract class Connector { diff --git a/packages/client/src/redux/pack.test.tsx b/packages/client/src/redux/pack.test.tsx new file mode 100644 index 0000000..98930ac --- /dev/null +++ b/packages/client/src/redux/pack.test.tsx @@ -0,0 +1,136 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import { Provider } from 'react-redux' +import { createStore, Dispatch } from 'redux' +import { pack } from './pack' +import { TStateSelector } from './TStateSelector' +import TestUtils from 'react-dom/test-utils' + +describe('pack', () => { + + interface IProps { + a: number + b: string + update(a: number, b: string): { + payload: {a: number, b: string}, + type: 'CHANGE', + } + c: string[] + } + + class PureComponent extends React.PureComponent { + update = () => { + this.props.update(1, 'one') + } + render() { + return ( + + ) + + return this.props.a + this.props.b + } + } + + function FunctionalComponent(props: IProps) { + return ( + + ) + } + + type LocalState = Omit + interface IState { + localState: LocalState + } + + function reduce( + state: IState = {localState: {a: 0, b: ''}}, + action: any, + ): IState { + switch (action.type) { + case 'CHANGE': + return { + ...state, + localState: { + ...action.payload, + }, + } + default: + return state + } + } + + function configurePureComponent( + getLocalState: TStateSelector, + ) { + return pack( + getLocalState, + (localState: LocalState) => localState, + { + update(a: number, b: string) { + return { + payload: {a, b}, + type: 'CHANGE', + } + }, + }, + PureComponent, + ) + } + + function configureFunctionalComponent( + getLocalState: TStateSelector, + ) { + return pack( + getLocalState, + (localState: LocalState) => localState, + { + update(a: number, b: string) { + return { + payload: {a, b}, + type: 'CHANGE', + } + }, + }, + FunctionalComponent, + ) + } + + const PackedPureComponent = configurePureComponent( + state => state.localState) + + const PackedFunctionalComponent = configureFunctionalComponent( + state => state.localState) + + it('creates a connected component', () => { + const store = createStore(reduce) + const element = document.createElement('div')! + ReactDOM.render( + + + , + element, + ) + expect(element.textContent).toBe('0') + TestUtils.Simulate.click(element.querySelector('button')!) + expect(element.textContent).toBe('1one') + }) + + it('should work with functional components', () => { + const store = createStore(reduce) + const element = document.createElement('div')! + ReactDOM.render( + + + , + element, + ) + expect(element.textContent).toBe('0') + TestUtils.Simulate.click(element.querySelector('button')!) + expect(element.textContent).toBe('1one') + }) + +}) diff --git a/packages/client/src/redux/pack.ts b/packages/client/src/redux/pack.ts index f9fac28..5171ea1 100644 --- a/packages/client/src/redux/pack.ts +++ b/packages/client/src/redux/pack.ts @@ -1,5 +1,5 @@ import { ComponentType, PureComponent } from 'react' -import { connect, Omit, MapDispatchToPropsParam } from 'react-redux' +import { connect, Omit, MapDispatchToPropsParam, Matching, GetProps, ResolveThunks } from 'react-redux' import { Dispatch } from 'redux' import { TStateSelector } from './TStateSelector' @@ -29,22 +29,21 @@ export function pack< LocalState, State, Props, - StateProps extends Partial, - DispatchProps extends Partial, + StateProps, + DispatchProps, + C extends React.ComponentType< + Matching, GetProps>> >( getLocalState: TStateSelector, mapStateToProps: (state: LocalState) => StateProps, mapDispatchToProps: MapDispatchToPropsParam, - Component: React.ComponentType, -): ComponentType< - Omit -> { - + Component: C, +) { return connect( (state: State) => { const l = getLocalState(state) return mapStateToProps(l) }, mapDispatchToProps, - )(Component as any) as any + )(Component) }