Skip to content

Instantly share code, notes, and snippets.

@stomita
Created October 13, 2018 02:18
Show Gist options
  • Save stomita/fdeb364f1e1581db87a9a6771f8b82b0 to your computer and use it in GitHub Desktop.
Save stomita/fdeb364f1e1581db87a9a6771f8b82b0 to your computer and use it in GitHub Desktop.
Legacy & New Context API / shouldUpdate is ignored in Function Component
/**
*
*/
import React, { createContext } from 'react';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';
import { render } from 'react-dom';
import { compose, lifecycle, withStateHandlers, shouldUpdate } from 'recompose';
/**
*
*/
export function provideContext(Ctx, provide) {
return (BaseComp) => (props) => (
<Ctx.Provider value={ provide(props) }>
<BaseComp { ...props } />
</Ctx.Provider>
);
}
/**
*
*/
export function consumeContext(Ctx) {
return (BaseComp) => (props) => (
<Ctx.Consumer>
{ context => (context ? <BaseComp { ...props } { ...context } /> : undefined) }
</Ctx.Consumer>
);
}
/**
*
*/
const initState = { count: 0 };
function reducer(state = initState, action) {
switch (action.type) {
case 'increment':
let { count } = state;
return { count: count + action.payload.num };
default:
return state;
}
}
const store = createStore(reducer);
const connector = connect(
({ count }) => ({ count }),
(dispatch) => ({
increment: (num) => dispatch({ type: 'increment', payload: { num } }),
})
);
/**
*
*/
const Context = createContext();
const parentCompEnhancer = compose(
lifecycle({
componentDidMount() {
console.log('componentDidMount');
const { increment } = this.props;
this._pid = setInterval(() => {
increment(1);
}, 1000);
},
componentWillUnmount() {
console.log('componentWillUnmount');
clearInterval(this._pid);
},
}),
provideContext(Context, ({ count }) => ({ count })),
);
const ParentComp = parentCompEnhancer(({ title, count, children }) => {
console.log('ParentComp#render', count);
return (
<div style={{ padding: 4 }}>
<h3>{ title }</h3>
<div>rendered: { Date.now() }</div>
<div>count: { count }</div>
{ children }
</div>
);
});
const ParentReduxComp = connector(ParentComp);
const ParentStateComp = withStateHandlers({ count: 0 }, {
increment: ({ count }) => (n) => ({ count: count + n }),
})(ParentComp);
/**
*
*/
const childCompEnhancer =
shouldUpdate((newProps, props) => {
const shouldUpdate = newProps.x !== props.x || newProps.y !== props.y;
console.log('ChildFuncComp#shouldUpdate', shouldUpdate);
return shouldUpdate;
});
const ChildFuncComp = childCompEnhancer(({ title, x, y, children }) => {
console.log('ChildFuncComp#render');
return (
<div style={{ border: '1px solid lightgray', margin: 4, padding: 4 }}>
<h3>{ title }</h3>
<div>rendered: { Date.now() }</div>
<div>x = { x }</div>
<div>y = { y }</div>
{ children }
</div>
);
});
class ChildClassComp extends React.Component {
shouldComponentUpdate(newProps) {
const props = this.props;
const shouldUpdate = newProps.x !== props.x || newProps.y !== props.y;
console.log('ChildClassComp#shouldComponentUpdate', shouldUpdate);
return shouldUpdate;
}
render() {
const { title, x, y, children } = this.props;
console.log('ChildClassComp#render');
return (
<div style={{ border: '1px solid lightgray', margin: 4, padding: 4 }}>
<h3>{ title }</h3>
<div>rendered: { Date.now() }</div>
<div>x = { x }</div>
<div>y = { y }</div>
{ children }
</div>
);
}
}
/**
*
*/
const grandChildCompEnhancer = consumeContext(Context)
const GrandChildComp = grandChildCompEnhancer(({ title, count }) => {
console.log('GrandChildComp#render');
return (
<div style={{ border: '1px solid lightgray', margin: 4, padding: 4 }}>
<h3>{ title }</h3>
<div>rendered: { Date.now() }</div>
<div>count in context: { count }</div>
</div>
);
});
/**
*
*/
const Root = () => {
console.log('Root#render');
return (
<div style={ { display: 'flex' } }>
<Provider store={ store }>
<ParentReduxComp title="Parent (Redux store counter)">
<ChildFuncComp title="Child (Function Component)" x={1} y={1}>
<GrandChildComp title="Grand Child" />
</ChildFuncComp>
<ChildClassComp title="Child (Class Component)" x={1} y={1}>
<GrandChildComp title="Grand Child" />
</ChildClassComp>
</ParentReduxComp>
</Provider>
<ParentStateComp title="Parent (state counter)">
<ChildFuncComp title="Child (Function Component)" x={1} y={1}>
<GrandChildComp title="Grand Child" />
</ChildFuncComp>
<ChildClassComp title="Child (Class Component)" x={1} y={1}>
<GrandChildComp title="Grand Child" />
</ChildClassComp>
</ParentStateComp>
</div>
);
};
render(<Root />, document.getElementById('root'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment