Last active
November 24, 2017 03:29
-
-
Save MHerszak/6dbeebf0fba14bc22dabbfefff533575 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import errors from 'feathers-errors'; | |
import { APP_REST } from './../../components/constants'; | |
import { setDisplayName } from './utils'; | |
import { forEach, omit } from './../../utils'; | |
function withStrategyCallback(callback) { | |
return function stateFunctionHOC(result) { | |
return function stateFunction(state, props) { | |
// callback will be false or a callback | |
return { | |
data: callback.call(this, result, state, props), | |
}; | |
}; | |
}; | |
} | |
function withService(callback) { | |
const handler = withStrategyCallback(callback); | |
return function getResult(result) { | |
return handler(result); | |
}; | |
} | |
const defaultEventTypes = ['created', 'updated', 'removed', 'patched']; | |
/** | |
* This function is supposed to do ui updates based on a specific data state. | |
* @param serviceName | |
* @param options | |
* @returns {rc} | |
*/ | |
export default function withServiceEvents( | |
serviceName, | |
options = { | |
// Name for debugging | |
name: 'default', | |
// The key for props which will be processed | |
key: 'data', | |
// SelectData should load data on componentWillMount | |
selectData() { console.log('no selectData function'); }, | |
}) { | |
/** | |
* The service will be plugged into app context. | |
*/ | |
return function rc(WrappedComponent) { | |
// Set context types | |
const contextTypes = { | |
...APP_REST | |
}; | |
/** | |
* Context of event hoc | |
*/ | |
class WithServiceEvents extends Component { | |
static contextTypes = contextTypes; | |
constructor(props, context) { | |
super(props, context); | |
// | |
this.options = options; | |
// get Events | |
const filteredEvents = Object.keys(options).filter((key) => defaultEventTypes.includes(key)); | |
// | |
this.events = filteredEvents.map(key => key); | |
// make sure context exists | |
const { app } = context; | |
// Is app actually available? | |
if (!app) { | |
throw new errors.NotFound(options.noErrMsg ? null : 'No app attached to WithSubscription HOC!'); | |
} | |
// ... that takes care of the subscription... | |
this.service = app.service(serviceName); | |
// set State | |
this.state = { | |
data: props[options.key], | |
}; | |
} | |
async componentWillMount() { | |
const { app } = this.context; | |
const data = await options.selectData(app.service(serviceName), this.props); | |
// console.log(data); | |
function updateDataArray(state, props) { | |
return { data }; | |
} | |
this.setState(updateDataArray); | |
} | |
componentDidMount() { | |
// register all events and handlers | |
forEach(this.events, (eventType) => { | |
// created, updated, patched and removed | |
this.service.on(eventType, this.handleChange(eventType)); | |
}); | |
} | |
// componentWillReceiveProps(nextProps) { | |
// This would be a source to pull in new data and setState | |
// but what happens is | |
// #1: You do an optimistic UI update | |
// #2: ComponentWillReceiveProps will be triggered and sets another state based | |
// on old data (not a desirable result) | |
// #3: Component is updated with old data and not the mutated change | |
// | |
// What should happen is that all events trigger a redux action call to pull in new data. | |
// } | |
componentWillUnmount() { | |
// remove all events | |
forEach(this.events, (eventType) => { | |
// created, updated, patched and removed | |
this.service.removeListener(eventType, this.handleChange(eventType)); | |
}); | |
} | |
data = () => ({ | |
data: this.state.data, | |
}); | |
handleChange = (eventType = '') => (result) => { | |
const handler = withService(options[eventType]); | |
// | |
if (this.component) { | |
return this.setState(handler(result)); | |
} | |
}; | |
render() { | |
const { data } = this.data(); | |
const rest = omit(this.props, 'data'); | |
return ( | |
<WrappedComponent | |
ref={(ref) => { this.component = ref; }} | |
data={data} | |
{...rest} | |
/> | |
); | |
} | |
} | |
WithServiceEvents.displayName = `WithServiceEvents(${setDisplayName(WrappedComponent)})`; | |
return WithServiceEvents; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment