import { StateProvider, useGetState } from './state';
const MyComp = () => {
const [state, actions] = useGetState();
[...]
};
const App = () => {
return (
<StateProvider>
<MyComp />
</StateProvider>
);
};
Last active
August 16, 2020 14:27
-
-
Save fiuzagr/91be100759c6d5d1f4e735f7802eb17f to your computer and use it in GitHub Desktop.
Simple React Flux with Hooks
This file contains hidden or 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
export const RESET_STATE = 'RESET_STATE'; | |
export const SET_ONBOARDING = 'SET_ONBOARDING'; | |
export const SET_OPEN_MENU = 'SET_OPEN_MENU'; | |
export const SET_FONT_SIZE = 'SET_FONT_SIZE'; |
This file contains hidden or 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 * as types from './action-types'; | |
const creator = (type) => (dispatch) => (payload, meta = {}) => { | |
console.debug('ACTION', type, { payload, meta }); | |
return dispatch({ type, payload, meta }); | |
}; | |
export const resetState = creator(types.RESET_STATE); | |
export const setOnboarding = creator(types.SET_ONBOARDING); | |
export const setOpenMenu = creator(types.SET_OPEN_MENU); | |
export const setFontSize = creator(types.SET_FONT_SIZE); |
This file contains hidden or 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
export default { | |
onboarding: false, | |
openMenu: null, | |
fontSize: 'medium', | |
}; |
This file contains hidden or 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 * as types from './action-types'; | |
const resetState = (_, { payload }) => payload; | |
const createSimpleReducer = (field) => (state, { payload }) => ({ | |
...state, | |
[field]: payload, | |
}); | |
const setOnboarding = createSimpleReducer('onboarding'); | |
const setOpenMenu = createSimpleReducer('openMenu'); | |
const setFontSize = createSimpleReducer('fontSize'); | |
export default { | |
[types.RESET_STATE]: resetState, | |
[types.SET_ONBOARDING]: setOnboarding, | |
[types.SET_OPEN_MENU]: setOpenMenu, | |
[types.SET_FONT_SIZE]: setFontSize, | |
}; |
This file contains hidden or 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, { | |
useState, | |
useEffect, | |
createContext, | |
useContext, | |
useReducer, | |
} from 'react'; | |
import { node } from 'prop-types'; | |
import useActions from './use-actions'; | |
import reducers from './reducers'; | |
import initialState from './initial-state'; | |
const dataStorage = localForage.createInstance({ | |
name: 'myStorage', | |
storeName: 'data', | |
}); | |
const reducer = (state, action) => { | |
if (reducers[action.type]) { | |
const newState = reducers[action.type](state, action); | |
console.debug('REDUCER', action.type, { state, newState }); | |
return newState; | |
} | |
return state; | |
}; | |
export const StateContext = createContext(); | |
// exposes [state, actions] from context | |
export const useGetState = () => useContext(StateContext); | |
export const StateProvider = ({ children }) => { | |
const [state, dispatch] = useReducer(reducer, initialState); | |
const [loadingState, setLoadingState] = useState(true); | |
const actions = useActions(dispatch); | |
// reset state with state in storage | |
useEffect(() => { | |
if (loadingState) { | |
dataStorage | |
.getItem('state') | |
.then((state) => state && actions.resetState(state)) | |
.catch(console.error) | |
.finally(() => setLoadingState(false)); | |
} | |
// useful for debug | |
if (process.env.NODE_ENV === 'development') { | |
window.__ACTIONS = actions; | |
} | |
}, [loadingState, actions]); | |
// save new state on storage and preserve previous state | |
useEffect(() => { | |
if (!loadingState) { | |
dataStorage | |
.getItem('state') | |
.then((previousState) => | |
dataStorage.setItem('previousState', previousState) | |
) | |
.then(() => dataStorage.setItem('state', state)) | |
.catch(console.error); | |
} | |
}, [state, loadingState]); | |
return loadingState ? ( | |
<div>Loading...</div> | |
) : ( | |
<StateContext.Provider value={[state, actions]}> | |
{children} | |
</StateContext.Provider> | |
); | |
}; | |
StateProvider.propTypes = { | |
children: node.isRequired, | |
}; |
This file contains hidden or 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 { useMemo } from 'react'; | |
import * as actions from './actions'; | |
const useActions = (dispatch) => | |
useMemo(() => Object.values(actions).map((action) => action(dispatch)), [dispatch]); | |
export default useActions; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment