In a react project, there is a globally available context for alert and messages. In any given component, I can use a context.setAlert() to put up a message.
I have some API fetching logic extracted into a utility function. It's not a component. Components import and use this function in various ways prior to render, sort of like this:
//MyComponent.js
import {fetchFromApi} from "../util"
import AlertContext from "../contexts/alert"
const MyComponent = () => {
const alertContext = useContext(AlertContext)
useEffect(() =>
fetchFromApi(...)
.then(() => alertContext.setAlert('All set'), [])
return <Something/>
}
So in fetchFromApi, I'd like to be able to use that AlertContext.setAlert method. Something like this:
// util.js
export const fetchFromApi = (params) =>
fetch("...")
.then(something)
.then(somethingelse)
.then(response => {
// set alert from the AlertContext is what I want to access
if (response.status === 500) alertContext.setAlert('oh no')
return response
})
I'm not sure if/how I can update a context state outside of a component. Is this possible?
You can mutate an object and set a setAlert property in the context provider. This object can be used by fetchApi. I assume fetchApi is only called from components within the Alert context so it's guaranteed to be set when fetchApi uses setAlert in the object:
const passSetAlert = { setAlert: (x) => x };
const AlertContext = React.createContext();// mutate passSetAlert
function AlertProvider(props) {
const [alert, setAlert] = React.useState('AA');
passSetAlert.setAlert = setAlert;
return (
<AlertContext.Provider value={{ alert, setAlert }}>
{props.children}
</AlertContext.Provider>
);
}
const fetchFromApi = (message) =>
setTimeout(() => {
passSetAlert.setAlert(message);
}, 2000);
function App() {
const [count, setCount] = React.useState(0);
const alertContext = React.useContext(AlertContext);
const click = () => {
const newCount = count + 1;
setCount(newCount);
fetchFromApi(newCount);
};
return (
<div>
<button onClick={click}>change alert</button>
Alert is: {alertContext.alert}
</div>
);
}
ReactDOM.render(
<AlertProvider>
<App />
</AlertProvider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>