Skip to content

Instantly share code, notes, and snippets.

@dkarmalita
Created October 30, 2020 08:09
Show Gist options
  • Save dkarmalita/f02424838b354695bc7ec78003eed2ee to your computer and use it in GitHub Desktop.
Save dkarmalita/f02424838b354695bc7ec78003eed2ee to your computer and use it in GitHub Desktop.
React | ContextStore
/* Some conponent which uses contextState and has be connected (subscribed) to the store data */
const MyContextUser = props => {
// console.log('render', props.id)
return (
<div>
<div>{ props.myContextState.count }</div>
{ props.title
&& (
<button
onClick={() => props.myContextState.setState({ count: props.myContextState.count + 1 })}
>
{ props.title }
</button>
) }
</div>
);
}
/*
Custom mapper which allows to convert any store update to new store state.
Please note the async operations example.
*/
const mapUpdateToState = (state, update, setState) => {
if(update.count === 1){
// setTimeout(() => setState({count: update.count + 100}), 2000)
exampleApi.getEmulate().then(() => setState({count: update.count + 100}))
}
if(update.count === 2){
return setState({count: update.count + 10})
}
console.log(update)
return ({ ...state, ...update });
}
/*
Creating the store.
Please, note that the mapper can be dropped off.
In this case, the default one is used:
(state, update) => ({ ...state, ...update })
*/
const store = new ContextStore(mapUpdateToState)
/*
State Provider can be simply used from the created state.
*/
const MyContextProvider = store.Provider;
/*
Like the redax's mapStateToProps, the ContextStore's mapContextStateToProps is responsibe
for mapping the context state to a component's props. It must be used with the store's connect.
*/
const mapContextStateToProps = (state, ownProps) => ({ ...ownProps, myContextState: state });
/* Connecting (subscribing) some context using component to the store state */
const MyContextUserConnected = store.connect(mapContextStateToProps)(MyContextUser);
/* Example of the provider/connected user pattern */
const AppView = () => (
<MyContextProvider>
<div>
<MyContextUserConnected title="Add" id="A"/>
</div>
</MyContextProvider>);
ReactDOM.render(
<AppView />,
document.getElementById('target'),
);
// context-store
function ContextStore(mapUpdateToState){
const Context = React.createContext({});
const mapUpdateToStateDefault = (state, update) => ({ ...state, ...update });
const createProvider = (mapUpdateToState = mapUpdateToStateDefault) => class extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
setContextState(update){
this.setState(mapUpdateToState(this.state, update, (u) => this.setContextState(u)))
}
render() {
return (
<Context.Provider value={
{ ...this.state, setState: (u) => this.setContextState(u) }
}
>
{ this.props.children }
</Context.Provider>
);
}
};
// connect(mapStateToProps, mapDispatchToProps)(ForgotPasswordContainer)
this.connect = mapStateToProps => AComponent => props => (
<Context.Consumer>
{ myContextState => (<AComponent {...mapStateToProps(myContextState, props)} />)}
</Context.Consumer>
);
this.Provider = createProvider(mapUpdateToState)
}
window.ContextStore = ContextStore;
window.exampleApi = {
async getMovies(){
return fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => {
return response.json();
})
},
async getEmulate(ms){
return new Promise(res => setTimeout(res, ms || 1000))
},
}
exampleApi.getMovies().then(console.log)
<!DOCTYPE html>
<!-- kard | v.20201024 | https://gist.github.com/dkarmalita/b336d1985b71bc4ff9147282b426d1c0 -->
<html>
<head>
<meta charset="utf-8" />
<title>React • in-browser</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"/>
</head>
<body>
<div id="target"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.6/es6-shim.min.js"></script>
<script src="https://unpkg.com/babel-regenerator-runtime@6.5.0/runtime.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.js"></script>
<script type="text/babel" src='context-store.js'></script>
<script type="text/babel" src='example-api.js'></script>
<script type="text/babel" src='app.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment