Last active
February 25, 2019 11:22
-
-
Save erodactyl/d20284d05357570ce828b97b8c297339 to your computer and use it in GitHub Desktop.
Context API implementation
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 from 'react'; | |
const createContext = (defaultState = undefined) => { | |
let state = defaultState; | |
let subscribers = []; | |
const subscribe = cb => { | |
// We call this function ourselves so no need to check the typeof cb === 'function' | |
subscribers.push(cb); | |
return () => { | |
subscribers = subscribers.filter(c => c !== cb); | |
}; | |
}; | |
const setState = value => { | |
state = value; | |
// Ping subscribers to let them know they need to rerender | |
subscribers.forEach(cb => cb()); | |
}; | |
// Rerendering the Provider is expensive, need to use PureComponent to avoid unnecessary renders | |
class Provider extends React.PureComponent { | |
componentWillMount() { | |
setState(this.props.value); | |
} | |
componentWillUpdate({ value }) { | |
setState(value); | |
} | |
render() { | |
return this.props.children; | |
} | |
} | |
const Consumer = ({ children }) => { | |
const [, setValue] = React.useState(true); | |
React.useEffect(() => { | |
// This "forceUpdate" callback is created only once, so no performance bottleneck | |
return subscribe(() => setValue(s => !s)); | |
}, []); | |
if (state === undefined) { | |
return null; | |
} | |
return children(state); | |
}; | |
return { Provider, Consumer }; | |
}; | |
export default createContext; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment