The new React Context API is amazing, however I seem to be always hacking my way around accessing it outside of a React ponent.. When you are inside a React function ponent or a React class ponent everything is great, however when you need to read or reset a value from the context (for example due to an async operation that happens in a fetch function) there is no easy way to do it..
So, is there a way to access the values in React Context Consumer outside a react ponent?
Later edit: I have inherited a Redux based project and slowly transition out of it. In the action creators, I have a logout function that purges the contents of the store:
export const logoutRequest = () => dispatch => {
navigate('Wele')
// Reset apollo data
client.resetStore()
persistor.purge()
// Reset context api data HERE
//
}
I could easily create a consumer in the ponent that calls the logout request, but that happens in 3 different ponents and I wouldn't want to duplicate the code there..
The new React Context API is amazing, however I seem to be always hacking my way around accessing it outside of a React ponent.. When you are inside a React function ponent or a React class ponent everything is great, however when you need to read or reset a value from the context (for example due to an async operation that happens in a fetch function) there is no easy way to do it..
So, is there a way to access the values in React Context Consumer outside a react ponent?
Later edit: I have inherited a Redux based project and slowly transition out of it. In the action creators, I have a logout function that purges the contents of the store:
export const logoutRequest = () => dispatch => {
navigate('Wele')
// Reset apollo data
client.resetStore()
persistor.purge()
// Reset context api data HERE
//
}
I could easily create a consumer in the ponent that calls the logout request, but that happens in 3 different ponents and I wouldn't want to duplicate the code there..
Share Improve this question edited Aug 28, 2019 at 19:22 Ciprian asked Aug 27, 2019 at 19:24 CiprianCiprian 1,2051 gold badge10 silver badges15 bronze badges 4- 4 Could you provide any example? It is not very clear, why you should access it outside the ponent. – Kyryl Stronko Commented Aug 27, 2019 at 19:27
- What exactly would accessing it outside of a ponent mean, though? It's useless without a provider, in the form of an ancestor ponent. So... outside of a ponent would mean accessing a context without a provider, which would get you... what, exactly? – Alex Broadwin Commented Aug 27, 2019 at 19:35
- Can you place your fetch function inside the ponent that owns the context provider? Or make the context an object, and provide setter functions to alter any necessary state? I just can't think of many situations in a React app where it's necessary to have code outside ponents, it definitely shouldn't be happening often. If you can post the code for some ponents where you're experiencing this, we can give you more specific advice. – Chris B. Commented Aug 27, 2019 at 19:38
- Added more specific example.. However, I think the use case is less important here.. – Ciprian Commented Aug 28, 2019 at 21:36
3 Answers
Reset to default 5You will eventually call logoutRequest()
in a ponent right? If you don't want to duplicate code you could create a custom hook:
const useLogout = () => {
const resetContext = React.useContext(SomeContext);
const logoutRequest = () => dispatch => {
navigate('Wele');
client.resetStore();
persistor.purge();
resetContext();
};
return logoutRequest;
}
Then you can call const logoutRequest = useLogout()
in your ponent.
You can do similar thing for asynchronous operations too.
React context is available only when the UI is available. This means that on background tasks you can't access it. But that doesn't mean that you can't access it "outside" of ponents.
I'll give an example where you can and can't use it outside a ponent:
- Not possible: You have a scheduled background task (using OS mechanism) to do some work (maybe fetch something), usually what happens is that the OS wakes up only a part of the app (assuming the app is in quit state) that handles the background task so that the UI will not be loaded (and interfere with what the user is currently doing) - so here the context won't be available
- Possible: You have a web socket that listens to events from the server (maybe a chat) and when an event arrives you wish to update the context. This is possible because of the fact that web sockets cannot run in the background (when the UI is ditched by the user/system - quit state) in react native (specifically). The way to do it is to wrap the socket event handlers with a class and initialize it with context dispatch function (saved as a private property of the class). In the same scope the handlers can access this private property to update the context.
A deeper explanation for background states:
You should separate between 3 background states
- Quit - the app wasn't open ever (since last phone boot) or was ditched by the system to free some resources. In this state no code is allowed to execute by the app, only if it is called by the system (e.g. scheduled task).
- Background - The app was opened but lost the user's focus (switched to another app for example). The UI is still in memory and available (including the context) and all app's code can continue running. On iOS, this state is not possible, on Android this is possible for a limited time, usually after that the OS will quit the app.
- Foreground - The app open and is in the user's focus. Almost everything is possible here.
No, you can't. The only way to update context it would be change the value sent to the Context.Provider.
For async actions to would usually save the result in a root ponent(or the ponent where the provider is rendered) and change that value that is sent. Or you could make a function in the context as show here https://reactjs/docs/context.html#updating-context-from-a-nested-ponent