Skip to content

Instantly share code, notes, and snippets.

@blainekasten
Created November 16, 2017 20:19
Show Gist options
  • Save blainekasten/b2b6df29a5cea2a0959a6813f3aa0d3b to your computer and use it in GitHub Desktop.
Save blainekasten/b2b6df29a5cea2a0959a6813f3aa0d3b to your computer and use it in GitHub Desktop.
RenderProps vs HOC
// This Component fetches data from a server and then renders its children.
// Important to remember that any time the parent component re-renders, this component re-renders also.
// I think the main difference is this version makes the fetching a Child while the HOC makes the fetching a Parent.
export class GetDataList extends Component {
props: { children: Function }
state = { dataList: null };
componentDidMount() {
// assume this is 1000s of records. Unpaginated so we can client side sort.
asyncFetchLargeDataList().then(dataList => this.setState({dataList}))
}
render() {
const { dataList, children: renderProp } = this.state;
return dataList ? renderProp(dataList) : null;
}
}
// Parent Component version.
export withDataList = (Comp) => <GetDataList>{dataList => <Comp dataList={dataList} />}</GetDataList>;
import { withDataList } from 'get-data-list';
export default class PerformantChild extends Component {
props: { dataList: Array<Object> }
constructor(props) {
super(props);
this.state = {
sort: 'asc',
dataList: this.computePropsAndSort(props.dataList),
}
}
componentWillReceiveProps(props) {
if (props.dataList !== this.props.dataList) {
this.setState({
dataList: this.computePropsAndSort(props.dataList)
});
}
}
computePropsAndSort(dataList) {
return dataList
.sort((a, b) => this.state.sort === 'asc'
? a.order < b.order
: a.order > b.order
)
.map((data => ({
...data,
computedProp: data.status === 0 & data.isFunctional ? 'Enabled' : 'Disabled',
});
}
switchSort = () => {
this.setState({ sort: this.state.sort === 'asc' ? 'desc' : 'asc' });
}
render() {
// Now rendering is cheap. Zero manipulation at render time.
return (
<div>
<div onClick={this.switchSort}>Functionality</div>
{this.state.dataList
.map(sortedList => (<div>{sortedList.computedProp}</div>))}
</div>
);
}
}
import { GetDataList } from 'get-data-list';
export default class UnperformantParent extends Component {
state = { sort: 'asc' }
switchSort = () => {
this.setState({ sort: this.state.sort === 'asc' ? 'desc' : 'asc' });
}
computePropsAndSort(dataList) {
return dataList
.sort((a, b) => this.state.sort === 'asc'
? a.order < b.order
: a.order > b.order
)
.map((data => ({
...data,
computedProp: data.status === 0 & data.isFunctional ? 'Enabled' : 'Disabled',
});
}
render() {
// Note that every time the header (Functionality) is clicked, the component is re-rendered. Which means the renderProp
// will give us back the same pure data, unsorted, uncomputed, and we'll have to do that again.
// Being a child of this component forces us into this position where we can't save the `dataList` in this component.
return (
<div>
<div onClick={this.switchSort}>Functionality</div>
<GetDataList>
{dataList => this
.computePropsAndSort(dataList)
.map(sortedList => (<div>{sortedList.computedProp}</div>))
}
</GetDataList>
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment