Created
March 17, 2020 16:40
-
-
Save james-gardner/45253f74d01a7031208ad462d4849bb5 to your computer and use it in GitHub Desktop.
useReducer vs Custom Hook
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, { createContext, useReducer, useContext } from 'react' | |
import PropTypes from 'prop-types' | |
const ServiceRequestContext = createContext() | |
export const initialState = { | |
serviceRequests: new Map(), | |
selectedTicketId: null, | |
pendingRequest: null | |
} | |
/** | |
* Action types. | |
*/ | |
export const SELECT_SERVICE_REQUEST = 'SELECT_SERVICE_REQUEST' | |
export const CREATE_SERVICE_REQUEST = 'CREATE_SERVICE_REQUEST' | |
export const LOAD_SERVICE_REQUEST = 'LOAD_SERVICE_REQUEST' | |
export const SAVE_SERVICE_REQUEST = 'SAVE_SERVICE_REQUEST' | |
export const LOAD_PENDING = 'LOAD_PENDING' | |
export const LOAD_SUCCESS = 'LOAD_SUCCESS' | |
export const LOAD_FAILURE = 'LOAD_FAILURE' | |
/** | |
* Action creators. | |
*/ | |
export const selectServiceRequest = ticketId => ({ | |
type: SELECT_SERVICE_REQUEST, | |
payload: { | |
ticketId | |
} | |
}) | |
export const createServiceRequest = payload => ({ | |
type: CREATE_SERVICE_REQUEST, | |
payload | |
}) | |
export const loadServiceRequest = payload => ({ | |
type: LOAD_SERVICE_REQUEST, | |
payload: { | |
ticketId | |
} | |
}) | |
export const saveServiceRequest = payload => ({ | |
type: SAVE_SERVICE_REQUEST, | |
payload | |
}) | |
/** | |
* Selectors. | |
*/ | |
export const getSelectedServiceRequest = state => | |
state.serviceRequests.get(state.selectedTicketId) | |
/** | |
* Reducer. Used for complex state transitions. | |
*/ | |
export const reducer = (state, action) => { | |
switch(action.type) { | |
case LOAD_PENDING: | |
return { | |
...state, | |
pendingRequest: action.payload.pendingRequest | |
} | |
case LOAD_FAILURE: | |
case LOAD_SUCCESS: | |
return { | |
...state, | |
pendingRequest: null | |
} | |
case SELECT_SERVICE_REQUEST: | |
return { | |
...state, | |
serviceRequests: state.serviceRequests.set(action.payload.ticketId, { | |
data: undefined | |
}), | |
selectedTicketId: action.payload.ticketId | |
} | |
default: | |
throw new Error('unknown action type'); | |
} | |
} | |
/** | |
* Async middleware. | |
* | |
* This middleware wraps the dispatch method to pick up on actions that have async dependencies | |
* such as data for different parts of the form. | |
* | |
* See: https://gist.github.com/astoilkov/013c513e33fe95fa8846348038d8fe42 | |
*/ | |
const middleware = dispatch => | |
action => { | |
switch (action.type) { | |
case LOAD_SERVICE_REQUEST: | |
dispatch({ | |
type: LOAD_PENDING, | |
payload: { | |
pendingRequest: null | |
} | |
}) | |
return | |
// Pass through to dispatch. | |
default: | |
return dispatch(action); | |
} | |
} | |
/** | |
* Provides a context which houses all selected SRs e.g. search selections. | |
*/ | |
export const ServiceRequestProvider = ({ children }) => { | |
const [state, dispatch] = useReducer(reducer, initialState) | |
return ( | |
<ServiceRequestContext.Provider value={[state, middleware(dispatch)]}> | |
{children} | |
</ServiceRequestContext.Provider> | |
) | |
} | |
ServiceRequestProvider.propTypes = { | |
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired | |
} | |
export const useServiceRequests = () => useContext(ServiceRequestContext) |
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 { useEffect, useState, useRef } from 'react' | |
import axios from 'axios' | |
export const useObject = (api, objectType, query) => { | |
const [ state, setState ] = useState({ | |
loading: true, | |
data: undefined, | |
error: undefined | |
}) | |
const ref = useRef() | |
const loadObject = async (objectType, query) => { | |
ref.current = axios.CancelToken.source() | |
setState({ data: undefined, error: undefined, loading: true }) | |
try { | |
const res = await api.get(`/os/${objectType}?${query}`, { | |
cancelToken: ref.current.token, | |
useCache: true | |
}) | |
setState({ data: res.data, loading: false }) | |
} catch (err) { | |
if (!axios.isCancel(err)) { | |
setState(state => ({ | |
...state, | |
loading: false, | |
error: true | |
})) | |
} | |
} | |
} | |
useEffect(() => { | |
loadObject(objectType, query) | |
return () => { | |
if (ref.current) { | |
ref.current.cancel() | |
} | |
} | |
}, [query]) | |
return state | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment