Skip to content

Instantly share code, notes, and snippets.

@ctavan
Created January 17, 2017 12:13
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ctavan/7219a3eca42f96a5c5f755319690bda7 to your computer and use it in GitHub Desktop.
Save ctavan/7219a3eca42f96a5c5f755319690bda7 to your computer and use it in GitHub Desktop.
mutatable react HOC
import hoistNonReactStatic from 'hoist-non-react-statics';
import React from 'react';
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
// See: https://facebook.github.io/react/docs/higher-order-components.html
export default function mutatable({ mutationName = 'mutate' } = {}) {
return (SourceComponent) => {
class Mutatable extends React.Component {
state = {
loading: false,
error: '',
};
submit = (event, variables, { handleError, handleSuccess } = {}) => {
event.preventDefault();
this.setState({ loading: true, error: '' });
this.props[mutationName]({ variables })
.then(() => {
console.log(`[${Mutatable.displayName}] Successful!`);
this.setState({ loading: false });
if (handleSuccess) {
handleSuccess();
}
})
.catch((error) => {
console.error(`[${Mutatable.displayName}] Failed!`, error);
this.setState({ loading: false, error: error.message });
if (handleError) {
handleError();
}
});
}
render() {
return (
<SourceComponent
{...this.props}
loading={this.state.loading}
error={this.state.error}
submit={this.submit}
/>
);
}
}
Mutatable.displayName = `Mutatable(${getDisplayName(SourceComponent)})`;
hoistNonReactStatic(Mutatable, SourceComponent);
return Mutatable;
};
}
import { graphql, compose } from 'react-apollo';
import gql from 'graphql-tag';
import React from 'react';
class Register extends React.Component {
static contextTypes = {
router: React.PropTypes.object,
}
handleSuccess = () => {
this.context.router.transitionTo('/home');
}
render() {
const { t, submit, loading, error } = this.props;
const { email, password } = this.state;
return (
<div>
{loading && (<div>Loading…</div>)}
<form
onSubmit={event => submit(
event,
{ email, password },
{ handleSuccess: this.handleSuccess },
)}
>
{error && (<div>{error}</div>)}
<input
name="email"
value={email}
onChange={event => this.setState({ email: event.target.value })}
/><br />
<input
type="password"
name="password"
value={password}
onChange={event => this.setState({ password: event.target.value })}
/><br />
<button type="submit" />
</form>
</div>
);
}
}
const RegisterUserMutation = gql`
mutation RegisterUser($email: String!, $password: String!) {
registerUser(email: $email, password: $password)
}
`;
export default compose(
graphql(RegisterUserMutation),
mutatable(), // Provides the props 'error' and 'loading' which can be used in the Register component,
// as well as the method 'submit' which needs to be called to trigger the mutation.
)(Register);
@sami616
Copy link

sami616 commented Apr 17, 2018

nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment