Created
October 13, 2018 02:18
-
-
Save stomita/fdeb364f1e1581db87a9a6771f8b82b0 to your computer and use it in GitHub Desktop.
Legacy & New Context API / shouldUpdate is ignored in Function Component
This file contains 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, { 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