Skip to content

Instantly share code, notes, and snippets.

@jabney
Last active January 22, 2020 20:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jabney/47ec952b82d354e77dde5703d2603bdd to your computer and use it in GitHub Desktop.
Save jabney/47ec952b82d354e77dde5703d2603bdd to your computer and use it in GitHub Desktop.
micro-react-redux: a minimal implementation of react-redux style provider and connect function
/**
* Minimal implementation of react-redux style provider and connect function.
*/
import React, { useState, useEffect, useContext } from 'react'
const StoreContext = React.createContext(null)
/**
* Wraps root component for providing store context, e.g.,
*
* <StoreProvider store={store}>
* <App />
* </StoreProvider>
*/
export const StoreProvider = ({ children, store }) => (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
)
/**
* Connect an individual component to the store, a la react-redux.
*
* @param {(state: any, props?: any) => {[key: string]: any}} mapState
* @param {(dispatch: (action: any) => void) => {[key: string]: (...args: any) => void}} mapDispatch
*/
export const connect = (mapState, mapDispatch) => (WrappedComponent) => (props) => {
const [, update] = useState(null)
// Get the store context (requires use of StoreProvider).
const store = useContext(StoreContext)
// Create a bound dispatch function.
const dispatch = store.dispatch.bind(store)
// Update on state changes.
const performUpdate = () => update(store.getState())
// Subscribe to store on mount, and do unsubscribe on unmount.
useEffect(() => store.subscribe(performUpdate), [])
// Get mapped state and dispatchers.
const state = typeof mapState === 'function' ? mapState(store.getState(), props) : {}
const dispatchers = typeof mapDispatch === 'function' ? mapDispatch(dispatch) : {}
// Apply state and dispatchers to wrapped component and render.
return <WrappedComponent {...props} {...state} {...dispatchers} />
}
/*** Store Provider ***
import { StoreProvider } from './micro-react-redux' // this gist
import createStore from './micro-redux' // see micro-redux gist
import reducer from './reducer' // create your own reducer
const App = () => <MyComponentTree />
const store = createStore(reducer)
export default () => (
<StoreProvider store={store}><App /></StoreProvider>
)
*/
/*** connect ***
const SomeComponent = (props) => {
return <MyComponent {...} />
}
function mapState(state) {
return {...}
}
function mapDispatch(dispatch) {
return {...}
}
export default connect(mapState, mapDispatch)(SomeComponent)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment