Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Commit

Permalink
Provide the last mapping results to the result props mapping functi…
Browse files Browse the repository at this point in the history
…on (#1620)

This allows the `props` mapping function to examine and use its prior
results, when acceptable, to preserve referential equality.
  • Loading branch information
jamesreggio authored and James Baxley committed Feb 16, 2018
1 parent 9dc155b commit c923f9d
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Change log

### vNext

* HoC `props` result-mapping function now receives prior return value as second argument.
* Fix errorPolicy when 'all' not passing data and errors

### 2.1.0-beta.2
Expand Down
8 changes: 7 additions & 1 deletion src/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ export default function graphql<
// wrapped instance
private wrappedInstance: any;

// last props returned from mapResultsToProps
private lastResultProps: TChildProps;

constructor(props: GraphqlProps, context: GraphqlContext) {
super(props, context);

Expand Down Expand Up @@ -354,7 +357,10 @@ export default function graphql<
[name]: result,
ownProps: this.props,
};
if (mapResultToProps) return mapResultToProps(newResult);
if (mapResultToProps) {
this.lastResultProps = mapResultToProps(newResult, this.lastResultProps);
return this.lastResultProps;
}

return { [name]: defaultMapResultToProps(result) };
}
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export interface OperationOption<
) =>
| QueryOpts<TGraphQLVariables>
| MutationOpts<TData, TGraphQLVariables>);
props?: (props: OptionProps<TProps, TData>) => TChildProps;
props?: (props: OptionProps<TProps, TData>, lastProps: TChildProps) => TChildProps;
skip?: boolean | ((props: any) => boolean);
name?: string;
withRef?: boolean;
Expand Down
68 changes: 68 additions & 0 deletions test/client/graphql/queries/reducer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,72 @@ describe('[queries] reducer', () => {
</ApolloProvider>,
);
});

it('passes the prior props to the result-props mapper', done => {
const query: DocumentNode = gql`
query thing {
getThing {
thing
}
}
`;
const expectedData = { getThing: { thing: true } };
const link = mockSingleLink({
request: { query },
result: { data: expectedData },
});
const client = new ApolloClient({
link,
cache: new Cache({ addTypename: false }),
});

interface Data {
getThing: { thing: boolean };
}

interface FinalProps {
wrapper: { thingy: { thing: boolean } },
refetch: () => any,
}

const withData = graphql<{}, Data, {}, FinalProps>(query, {
props: ({ data }, lastProps: FinalProps) => {
const refetch = data!.refetch!;
let wrapper = { thingy: data!.getThing! };

// If the current thingy is equal to the last thingy,
// reuse the wrapper (to preserve referential equality).
if (lastProps && lastProps.wrapper.thingy === wrapper.thingy) {
wrapper = lastProps!.wrapper!;
}

return { wrapper, refetch };
},
});

let counter = 0;
class Container extends React.Component<FinalProps> {
componentWillReceiveProps(nextProps: FinalProps) {
expect(stripSymbols(nextProps.wrapper.thingy)).toEqual(expectedData.getThing);
if (counter === 1) {
expect(nextProps.wrapper).toEqual(this.props.wrapper);
done();
} else {
counter++;
nextProps.refetch();
}
}
render() {
return null;
}
}

const ContainerWithData = withData(Container);

renderer.create(
<ApolloProvider client={client}>
<ContainerWithData />
</ApolloProvider>,
);
});
});

0 comments on commit c923f9d

Please sign in to comment.