Skip to content

Instantly share code, notes, and snippets.

@adambard
Created September 9, 2017 00:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adambard/fadb2e0ca06054ab899fe0d54b8f5bbf to your computer and use it in GitHub Desktop.
Save adambard/fadb2e0ca06054ab899fe0d54b8f5bbf to your computer and use it in GitHub Desktop.
React GRPC HOC
import * as jspb from 'google-protobuf'
import { Code, grpc } from 'grpc-web-client'
import React from 'react'
export interface RPCResponseData<TResult, TOwnProps> {
ownProps: TOwnProps
loading: boolean
result: TResult | null
status: Code | null
statusMessage: string
}
export type RPCPropertyMapper<TOwnProps, TResult, TResultProps> =
(data: RPCResponseData<TResult, TOwnProps>) => TResultProps
interface RPCProviderState<TResultProps> {
result: TResultProps | null
}
type Component<TProps> =
React.StatelessComponent<TProps>
| React.ComponentClass<TProps>
interface MapRPCOptions<TOwnProps, TRequest extends jspb.Message, TResult extends jspb.Message, TResultProps> {
method: grpc.UnaryMethodDefinition<TRequest, TResult>,
host: string,
request: TRequest | ((props: TOwnProps) => TRequest),
props: RPCPropertyMapper<TOwnProps, TResult, TResultProps>
}
export function wrapRPCProvider<TOwnProps extends object,
TRequest extends jspb.Message,
TResult extends jspb.Message,
TResultProps extends object>(
options: MapRPCOptions<TOwnProps, TRequest, TResult, TResultProps>
) {
return (Comp: Component<TOwnProps & TResultProps>) => {
type State = RPCProviderState<TResultProps>
return class RPCProvider extends React.Component<TOwnProps, State> {
static displayName = `RPCProvider(${Comp.displayName || Comp.name})`
componentWillMount() {
this.setState({
result: options.props({
loading: true,
ownProps: this.props,
result: null,
status: null,
statusMessage: ''
})
})
grpc.unary(options.method, {
host: options.host,
request: (options.request instanceof Function) ? options.request(this.props) : options.request,
onEnd: ({status, message, statusMessage}: grpc.UnaryOutput<TResult>) => {
this.setState({
result: options.props({
loading: false,
result: message,
ownProps: this.props,
status,
statusMessage
})
})
}
})
}
render() {
const {result} = this.state
const props = Object.assign({}, this.props, result)
return <Comp {...props}/>
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment