-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use context across different components #4517
Comments
@SMJ93 When a component is used in JSX: |
@guyca I see, and usually (with web and other nav libraries) we wrap the provider around the entire app once, but with RNN we wrap it around each screen which invokes the constructor multiple times? No I've not tried that, do you have any good links / examples showing how to do that? I've not done it before. |
Thanks @guyca 👍 |
I'm having the same problem, I'm used to wrap the whole application within one or many Context.Provider's so that every subcomponent will have the same provider[s]. In Game and Friends I have a Context.Consumer and the AppStateProvider component is a React component that returns Context.Provider Im registrering the components like this, but ofcourse they don't share the same Provider so that won't work.
How did you solve this @SMJ93 ? |
I've copied the same code as @guyca wrote in the example – and on my iOS simulator its not working very good, the components isen't re-rendering when the state changes but it seems that they do share the state. I'm sure this will be improved in the future but for now it seems like I should try implementing Redux instead. |
Here are my files with it working: GlobalContext - works like normal context, but notice we also have
registerHomeScreen
register settings screen
Note: I am using hooks Settings screen
Home screen:
The count value is the same on both screens. Hope this helps! |
I ended up solving this (for now) by using the new Provider API, but explicitly passing the context around: // First in the stack (parent scene)
Navigation.registerComponent(
SCENE.PARENT,
() => props => (
<Provider>
<Parent {...props} />
</Provider>
),
() => Parent)
// Next in the stack (child scene, in my case a modal)
Navigation.registerComponent(
SCENE.CHILD,
() => props => (
<Provider value={props.ctx}>
<Child {...props} />
</Provider>
),
() => Child)
// Then from the parent
Navigation.showOverlay({
component: SCENES.CHILD,
options: { ... },
passProps: { ctx }, // This being the context from the parent: useContext(Provider)
}); I'm not sure I'm going to like this if I have to repeat a lot, but for this application I don't have very deep stacks. I don't mind setting up the new provider instance for each screen. |
Reopen please? This is still a problem |
Hey @guyca, I've just updated my project to RN 0.60 and enabled hermes, but the Does react-native-navigation have a proper solution to the context API yet? |
I was directed to this solution by @sijad on Discord#need-help. In doing this change I was able to get the update method from either a import React from 'react';
import shortid from 'shortid';
declare type GlobalProviderProps = {
count: number,
updateCount: Function
};
declare type GlobalProviderStateType = {
context: GlobalProviderProps
};
const updateCount = (): void => {
globalStateValue.count = globalStateValue.count + 1;
console.log(globalStateValue, GlobalContextProviderInstances);
for (let instanceId in GlobalContextProviderInstances) {
GlobalContextProviderInstances[instanceId].forceUpdate();
}
};
const defaultState: GlobalProviderProps = {
count: 0,
updateCount: updateCount
};
let GlobalContextProviderInstances: any = {};
const stateAwareContext = (component: any): any =>
new Proxy(defaultState, {
set(obj: any, prop: any, value: any): boolean {
obj[prop] = value;
component.setState({ context: stateAwareContext(component) });
// Indicate proxy success
return true;
}
});
const globalStateValue: GlobalProviderProps = defaultState;
const GlobalContext = React.createContext(defaultState);
class GlobalProvider extends React.Component<GlobalProviderProps, GlobalProviderStateType> {
private _instanceId: string = shortid.generate();
constructor(props: GlobalProviderProps) {
super(props);
this.state = {
context: stateAwareContext(this)
};
}
shouldComponentUpdate(): boolean { return true; }
componentDidMount(): void {
GlobalContextProviderInstances[this._instanceId] = this;
}
componentWillUnmount(): void {
delete GlobalContextProviderInstances[this._instanceId];
}
public render(): JSX.Element {
const value = {
count: this.state.context.count,
updateCount: updateCount
};
return (
<GlobalContext.Provider value={value}>
{this.props.children}
</GlobalContext.Provider>
);
}
}
export { GlobalContext, GlobalProvider }; |
@jasondenney Glad to hear it helped you! There is a problem with this solution as it uses |
Yea, and this problem is a kind of break deal for the decision to use this library or give up and use react-navigation. |
I don't see it in backlog :( |
Hey @EJohnF @SMJ93 From the React docs:
I'm not sure what was the motivation for making Context only support trees of react components, and not... any react components. Even if they don't share the same root. |
Thanks for the explanation @guyca. Yeah I guess that is where React Native Navigation won't work as each screen has a different tree, compared React Navigation which is all one tree 😕 I will try to find some time to see if there are any other workarounds as I was really hoping to avoid moving to React Navigation as this libraries feels so much smoother than react-navigation! I guess another option is to use Redux, but I was hoping to avoid that! |
can you please give https://github.com/atlassian/react-sweet-state a try? |
If that's the route you want to take there is also https://github.com/CharlesStover/reactn |
So, does this mean we should go for redux? |
Played around with context api, tried to get the wrapped component to rerender after global context was updated - this is what I came up with. Note: this commit makes the playground app use a newer js core as the js core which shipped with RN on Android is missing javascript Proxy. Closes wix#4517
@sijad 's suggestion is great. I'm having a great experience with that package so far. |
you can use these libraries to tackle React Navigation limitaions. https://github.com/pmndrs/jotai |
Issue Description
Great work with adding support for React context API @guyca!
I've managed to get context working as expected for individual components:
Is there a way we can share the context across components / screens?
Steps to Reproduce / Code Snippets / Screenshots
If I update the snippet above to:
I would expect the Alerts context to be the same on each screen, but it creates a new context for each screen.
alerts: [ {alert: 1} ]
alerts: []
alerts: [ {alert: 1} ]
I would like the context
alerts: [ {alert: 1} ]
available on all screens.Environment
The text was updated successfully, but these errors were encountered: