Last active
September 29, 2022 02:03
-
-
Save jimkeller/8f338c91d9772fe1c932e597dcad2eb2 to your computer and use it in GitHub Desktop.
Example of dependency injection in React using Context
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
/** | |
* | |
* This file creates a React Context to hold the functionality for connecting to the | |
* employee data endpoint. | |
* | |
* I'm using Context here to mimic dependency injection so that the | |
* client can be more easily mocked for testing, or swapped out in the future. | |
* | |
* You can import EmployeeDataProvider from this file then | |
* wrapping a child component in <EmployeeDataProvider></EmployeeDataProvider> to give the component | |
* access to the data provider. | |
* | |
*/ | |
import React from "react"; | |
import { createContext, useContext } from "react"; | |
import PropTypes from 'prop-types'; | |
import axios from "axios"; | |
import regeneratorRuntime from "regenerator-runtime"; // eslint-disable-line no-unused-vars | |
/* | |
* Create the context | |
*/ | |
const EmployeeDataClientContext = createContext(undefined); | |
/** | |
* | |
* This hook function is basically just a helper so that components themselves don't have | |
* to use createContext(). Instead we can provide this hook and do some error checking here. | |
*/ | |
export const useEmployeeDataClient = () => { | |
const context = useContext(EmployeeDataClientContext); | |
if (context == 'undefined') { | |
throw new Error('EmployeeClientContext was not provided. Make sure your component is a child of the EmployeeClient'); | |
} | |
return context; | |
} | |
/** | |
* The actual provider for the context, with the service within it. | |
*/ | |
const EmployeeDataProvider = ({children}) => { | |
const endpoint_base_url = "http://localhost:3035/employees/" | |
/* Set up our service within this provider */ | |
const employee_data_client_service = { | |
async getResults(id) { | |
const response = await axios.get(`${endpoint_base_url}/${id}`) | |
.catch((err) => { | |
throw new Error("Error fetching results."); | |
}); | |
if (response.data.results) { | |
return response.data.results; | |
} | |
} | |
} | |
/** | |
* Set up an EmployeeDataClient provider component for this context. | |
* This essentially allows us to provide employee data fetching functionality | |
* to other components as if it were an injected service. | |
*/ | |
return( | |
<> | |
<EmployeeDataClientContext.Provider value={employee_data_client_service}> | |
{children} | |
</EmployeeDataClientContext.Provider> | |
</> | |
) | |
} | |
EmployeeDataProvider.propTypes = { | |
children: PropTypes.node | |
} | |
export default EmployeeDataProvider; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment